ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Combine_Chap5_CombiningOperators
    Combine 2021. 11. 26. 17:42
    import UIKit
    import Combine
    
    var greeting = "Hello, playground"
    
    var subscriptions = Set<AnyCancellable>()
    
    func example(of name: String, closure: () -> Void) {
        print("--------------------------\(name)--------------------------")
        closure()
    }
    
    example(of: "prepend(Output...)") {
        let publisher = [3,4].publisher
        
        publisher
            .prepend(1,2)
            .prepend(-1,0)
            .sink(receiveValue: {print($0)})
            .store(in: &subscriptions)
    }
    
    example(of: "prepend(Sequence)") {
        let publisher = [5,6,7].publisher
        
        publisher
            .prepend([3,4])
            .prepend(Set(1...2)) // can be printed as 1,2 or 2,1
            .prepend(stride(from: 6, to: 12, by: 2)) // stride: 보폭, not including an end value
            .sink(receiveValue: {print($0)})
            .store(in: &subscriptions)
    }
    // stride : Returns a sequence from a starting value to, but not including, an end value, stepping by the specified amount.
    
    
    example(of: "prepend(Publisher)") {
        let publisher1 = [3,4].publisher
        let publisher2 = [1,2].publisher
        
        publisher1
            .prepend(publisher2)
            .sink(receiveValue: {print($0)})
            .store(in: &subscriptions)
    }
    
    
    example(of: "prepend(Publisher) #2") {
        
        let publisher1 = [3,4].publisher
        let publisher2 = PassthroughSubject<Int, Never>()
        
        publisher1
            .prepend(publisher2)
            .sink(receiveValue: {print($0)})
            .store(in: &subscriptions)
        
        publisher2.send(1)
        publisher2.send(2)
        publisher2.send(3)
        publisher2.send(completion: .finished)
    }
    
    // PassthroughSubject: you can push values to manually.
    
    example(of: "append") {
        let publisher = [1,2].publisher
        
        publisher
            .append(3,4)
            .sink(receiveValue: {print($0)})
            .store(in: &subscriptions)
    }
    
    example(of: "append #2") {
        let publisher1 = [1].publisher
        
        let publisher2 = PassthroughSubject<Int, Never>()
        
        publisher2
            .append(publisher1)
            .sink(receiveValue: {print($0)})
            .store(in: &subscriptions)
    
        publisher2.send(2)
        publisher2.send(3)
        publisher2.send(completion: .finished)
        
    }
    
    example(of: "append(Sequence)") {
      
      let publisher = [1, 2, 3].publisher
      publisher
        .append([4, 5])
        .append(Set([6, 7]))
        .append(stride(from: 8, to: 11, by: 2)) // 4
        .sink(receiveValue: { print($0) })
        .store(in: &subscriptions)
    }
    
    example(of: "append(publisher)") {
        let publisher1 = [1,2].publisher
        
        let publisher2 = [3,4].publisher
        
        publisher2
            .append(publisher1)
            .sink(receiveValue: {print($0)})
            .store(in: &subscriptions)
    }
    
    
    example(of: "switchToLatest") {
        let publisher1 = PassthroughSubject<Int, Never>()
        let publisher2 = PassthroughSubject<Int, Never>()
        let publisher3 = PassthroughSubject<Int, Never>()
        
        // Create a second PassthroughSubject that accepts other PassthroughSubjects
        let publishers = PassthroughSubject<PassthroughSubject<Int, Never>, Never>()
        
        publishers
        // Use switchToLatest on your publishers. Now, every time you send a different publisher through the publishers subject, you switch to the new one and cancel the previous subscription.
            .switchToLatest()
            .sink(receiveCompletion: { _ in print("Completed!")}, receiveValue: { print($0)})
            .store(in: &subscriptions)
        
    //    Send publisher1 to publishers and then send 1 and 2 to publisher1.
        publishers.send(publisher1)
        publisher1.send(1)
        publisher1.send(2)
        
    //    Send publisher2, which cancels the subscription to publisher1. You then send 3 to publisher1, but it’s ignored, and send 4 and 5 to publisher2, which are pushed through because publisher2 is the current subscription.
        publishers.send(publisher2)
        publisher1.send(3)
        publisher2.send(4)
        publisher2.send(5)
        
        publishers.send(publisher3)
        publisher2.send(6)
        publisher3.send(7)
        publisher3.send(8)
        publisher3.send(9)
        
    //    Finally, you send a completion event to the current publisher, publisher3, and another completion event to publishers. This completes all active subscriptions.
        publisher3.send(completion: .finished)
        publishers.send(completion: .finished)
    }
    
    //example(of: "switchToLatest - Network Request") {
    //    let url = URL(string: "https://source.unsplash.com/random")!
    //    // 1
    //    func getImage() -> AnyPublisher<UIImage?, Never> {
    //
    //        return URLSession.shared
    //            .dataTaskPublisher(for: url)
    //        // 2 Create a PassthroughSubject to simulate user taps on a button.
    //            .map { data, _ in UIImage(data: data) }
    //            .print("image")
    //            .replaceError(with: nil)
    //            .eraseToAnyPublisher()
    //    }
    //        let taps = PassthroughSubject<Void, Never>()
    //
    //        taps
    //            .map { _ in getImage() } // 3
    //            .switchToLatest() // 4
    //            .sink(receiveValue: { _ in })
    //            .store(in: &subscriptions)
    //        // 5
    //        taps.send()
    //
    //        DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
    //            print("first tap has sended")
    //            taps.send()
    //        }
    //        DispatchQueue.main.asyncAfter(deadline: .now() + 3.1) {
    //            print("second tap has sended")
    //            taps.send()
    //        }
    //}
    //// 3 : Upon a button tap, map the tap to a new network request for a random image by calling getImage(). This essentially transforms Publisher<Void, Never> into Publisher<Publisher<UIImage?, Never>, Never> — a publisher of publishers.
    //
    //// 4 : Use switchToLatest() exactly like in the previous example, since you have a publisher of publishers. This guarantees only one publisher will emit values, and cancel any previous subscriptions.
    //
    //// 5 : Simulate three delayed button taps using a DispatchQueue. The first tap is immediate, the second tap comes after three seconds, and the last tap comes just a tenth of a second after the second tap.
    
    
    
    example(of: "merge(with:)") {
        
        let publisher1 = PassthroughSubject<Int, Never>()
        let publisher2 = PassthroughSubject<Int, Never>()
        
        publisher1
            .merge(with: publisher2)
            .sink(receiveCompletion: { _ in print("Completed")}, receiveValue: {print($0)})
            .store(in: &subscriptions)
        
        publisher1.send(1)
        publisher1.send(2)
        
        publisher2.send(3)
        
        publisher1.send(4)
        
        publisher2.send(5)
        
        // for publisher1 to be finished, both of them should be done.
        publisher1.send(completion: .finished)
        publisher2.send(completion: .finished)
    }
    
    example(of: "combineLatest") {
        let publisher1 = PassthroughSubject<Int, Never>()
        let publisher2 = PassthroughSubject<String, Never>()
        
        publisher1
            .combineLatest(publisher2)
            .sink(receiveCompletion: { _ in print("Completed")}, receiveValue: {print("P1: \($0) P2: \($1)")})
            .store(in: &subscriptions)
        
        publisher1.send(1)
        publisher1.send(2)
        
        publisher2.send("a")
        publisher2.send("b")
        
        publisher1.send(3)
        publisher2.send("c")
        
        publisher1.send(completion: .finished)
        publisher2.send(completion: .finished)
    }
    
    
    example(of: "zip") {
        let publisher1 = PassthroughSubject<Int, Never>()
        let publisher2 = PassthroughSubject<String, Never>()
        
        publisher1
    //        .combineLatest(publisher2)
            .zip(publisher2)
            .sink(receiveCompletion: { _ in print("Completed")}, receiveValue: {print("P1: \($0) P2: \($1)")})
            .store(in: &subscriptions)
        
        publisher1.send(1)
        publisher1.send(2)
        
        publisher2.send("a")
        publisher2.send("b")
        
        publisher1.send(3)
        publisher2.send("c")
        publisher2.send("d")
        
        publisher1.send(completion: .finished)
        publisher2.send(completion: .finished)
    }
    
    
    /*
    Key points
    In this chapter, you learned how to take different publishers and create meaningful combinations with them. More specifically, you learned that:
    • You can use the prepend and append families of operators to add emissions from one publisher before or after the original publisher.
    • While switchToLatest is relatively complex, it’s extremely useful. It takes a publisher that emits publishers, switches to the latest publisher and cancels the subscription to the previous publisher.
    • merge(with:) lets you interleave values from multiple publishers.
    • combineLatest emits the latest values of all combined publishers whenever any of them emit a value, once all of the combined publishers have emitted at least one value.
    • zip pairs emissions from different publishers, emitting a tuple of pairs after all publishers have emitted an value.
    • You can mix combination operators to create interesting and complex relationships between publishers and their emissions.
    */

    'Combine' 카테고리의 다른 글

    Combine-Chap7_Sequence Operator  (0) 2021.12.10
    Combine_Chap2_Publishers&Subscribers  (0) 2021.11.23
    Combine_Chap4_FilteringOperators  (0) 2021.11.21
    Combine_Chap3_TransformingOperators  (0) 2021.11.21
    Swift - Combine  (0) 2021.11.16
Designed by Tistory.