Combine

Combine_Chap3_TransformingOperators

iosswift 2021. 11. 21. 00:13
import UIKit
import Combine
import Foundation

var subscriptions = Set<AnyCancellable>()

func example(of name: String, closure: @escaping () -> Void) {
    print("-------------------- \(name) --------------------")
    closure()
}

example(of: "collection") {
    
//    var subscriptions = Set<AnyCancellable>()
    
    ["A","B","C","D","E"].publisher
//        .collect()
        .collect(2)
        .sink(receiveCompletion: {print($0)},
              receiveValue: {print($0)})
        .store(in: &subscriptions)
    
//     publisher: Publishers.Sequence<[String], Never>
//     : A Combine publisher that publishes each member of the sequence as a separate element.
    
//    func collect() -> Result<[Publishers.Sequence<Elements, Failure>.Output], Failure>.Publisher
    
//     .sink(receiveCompletion: <#T##((Subscribers.Completion<Never>) -> Void)##((Subscribers.Completion<Never>) -> Void)##(Subscribers.Completion<Never>) -> Void#>, receiveValue: <#T##((String) -> Void)##((String) -> Void)##(String) -> Void#>)
//     Attaches a subscriber with closure-based behavior.
    
//        .store(in: &<#T##Set<AnyCancellable>#>)
//     Stores this type-erasing cancellable instance in the specified set
}


example(of: "map") {
//    var subscriptions = Set<AnyCancellable>()
    
    let formatter = NumberFormatter()
    formatter.numberStyle = .spellOut // transform Number Into String
    
    [123,4,56].publisher
        .map {
            formatter.string(for: NSNumber(integerLiteral: $0)) ?? ""
        }
        .sink(receiveValue: {print($0)})
        .store(in: &subscriptions)
//        .sink(receiveValue: <#T##((String) -> Void)##((String) -> Void)##(String) -> Void#>)
//    Attaches a subscriber with closure-based behavior to a publisher that never fails.
}



func quadrantOf(x: Int, y: Int) -> String {
    switch (x,y) {
    case (x,y) where x > 0 && y > 0 : return "1"
    case (x,y) where x < 0 && y > 0 : return "2"
    case (x,y) where x < 0 && y < 0 : return "3"
    case (x,y) where x > 0 && y < 0 : return "4"
    default: return "boundary"
    }
}

struct Coordinate {
    let x: Int
    let y: Int
}


example(of: "map key paths") {
    
//    var subscriptions = Set<AnyCancellable>()
    
    // 1 Create a publisher of Coordinates that will never emit an error
    let publisher = PassthroughSubject<Coordinate, Never>()
    
    // 2 Begin a subscription to the publisher
    publisher
    // 3 Map into the x and y properties of Coordinate using their key paths
        .map(\.x, \.y)
        .sink { x, y in
            // 4 print a statement that indicates the quadrant of the provide x and y values
            print("The coordinate at (\(x), \(y)) is in quadrant", quadrantOf(x: x, y: y))
        }
        .store(in: &subscriptions)
    // 5 Send some coordinates through the publisher.
    publisher.send(Coordinate(x: 10, y: -8))
    publisher.send(Coordinate(x: 0, y: 5))
   
//            .map(<#T##keyPath: KeyPath<Coordinate, T>##KeyPath<Coordinate, T>#>)
//         publishes a value of key path
    
//    publisher.send(<#T##input: Coordinate##Coordinate#>)
//     send a value to the subscriber
    
//    let publisher2 = PassthroughSubject<Int, Never>()
//     PassthroughSubject: A subject that broadcasts elements to downstream subscribers
    
}


example(of: "tryMap") {
//    var subscriptions = Set<AnyCancellable>()
    // 1 Create a publisher of a string representing a directory name that does not exist
    Just("Directory name that does not exist")
    // 2.  Use trymap to attempt to get the contents of the nonexistent directory.
        .tryMap { try
            FileManager.default.contentsOfDirectory(atPath: $0)}
    // 3. Receive and print out any values or completion events.
        .sink(receiveCompletion: {print($0)}, receiveValue: {print($0)})
        .store(in: &subscriptions)
    
    
    // A publisher that emits an output to each subscriber just once, and then finishes
    //    Just(<#T##output: _##_#>)
    // initializes a publisher that emits the specified output just once

    //        .tryMap(<#T##transform: (String) throws -> T##(String) throws -> T#>)
    // Transforms all elements from the upstream publisher with a provided error-throwing closure.

}




public struct Chatter {
    public let name: String
    public let message: CurrentValueSubject<String, Never>
    
    public init(name: String, message: String) {
        self.name = name
        self.message = CurrentValueSubject(message)
//         CurrentValueSubject: A subject that wraps a single value and publishes a new element whenever the value changes
    }
}

example(of: "flatMap") {

    // 1 Create two instances of Chatter: charlotte and james
    let charlotte = Chatter(name: "Charlotte", message: "Hi, I'm Charlotte!")
    let james = Chatter(name: "James", message: "Hi, I'm James!")
    // 2 Create a chat publisher initialized with charlotte
    let chat = CurrentValueSubject<Chatter, Never>(charlotte)
    
    // 3 Subscribe to chat and print out the message of any received Chatter structure.
    chat
        // 6. flatmap into the Chatter structure message publisher.
//        .flatMap{ $0.message }
        .flatMap(maxPublishers: .max(2)) { $0.message }
//        .sink(receiveValue: {print($0.message.value)})
    // 7. Change the handler to print the vlaue received, which is now a string, not a Chatter instance.
        .sink(receiveValue: {print($0)})
        .store(in: &subscriptions)
    
    // 4 Change Charlotte's message
    charlotte.message.value = "Charlotte: How's it going?"
    
    // 5 Change the chat publisher's current value to james.
    chat.value = james
    
    james.message.value = "James: Doing great. You?"
   charlotte.message.value = "Charlotte: I'm doing fine thanks."
    
    // 8 Create a third Chatter instance.
    let morgan = Chatter(name: "Morgan",
                         message: "Hey guys, what are you up to?")
    // 9 Add that Chatter onto the chat publisher.
    chat.value = morgan
    // 10 Change Charlotte’s message.
    charlotte.message.value = "Did you hear something?"
    
}


example(of: "replaceNil") {
//    var subscriptions = Set<AnyCancellable>()
    
    ["A", nil, "C"].publisher
        .replaceNil(with: "-")
        .map{$0!}
        .sink(receiveValue: {print($0)})
        .store(in: &subscriptions)
}


example(of: "replaceEmpty(with:)") {
    // 1. Create an empty publisher that immediately emits a completion event.
    let empty = Empty<Int, Never>()
    
//    2. Subscribe to it, and print received events.
    empty
        .replaceEmpty(with: 1)
    // replaces empty stream with the provided element
//        .replace
        .sink(receiveCompletion: {print($0)},
              receiveValue: {print($0)})
        .store(in: &subscriptions)
}

example(of: "scan") {
    // 1
    var dailyGainLoss: Int {.random(in: -10 ... 10)}
    var count = 0
    // 2
    let august2021 = (0 ..< 22)
        .map { _ in dailyGainLoss }
        .publisher
    
    august2021
        .scan(50) { latest, current in
            max(0, latest + current)
        }
        .sink(receiveValue: {
//            print(count + $0)
            count += 1
            print("\(count) : \($0)")
        })
        .store(in: &subscriptions)
}