ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Ch5. Combining Operators
    Ray Wenderlich/Combine 2021. 2. 12. 01:51

    Prepending

    prepend(Output...)

    let publisher = [3, 4].publisher
      
    publisher
      .prepend(1, 2)
      .sink(receiveValue: { print($0) })
      .store(in: &subscriptions)
    
    1
    2
    3
    4
    

    prepend(Sequence)

    Sequence프로토콜을 따르는 타입을 전달받을 수 있음

    let publisher = [5, 6, 7].publisher
      
    publisher
      .prepend([3, 4])
      .prepend(Set(1...2))
    	.prepend(stride(from: 6, to: 11, by: 2))
      .sink(receiveValue: { print($0) })
      .store(in: &subscriptions)
    
    6
    8
    10
    1
    2
    3
    4
    5
    6
    7
    

    prepend(Publisher)

    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(completion: .finished)
    
    1
    2
    3
    4
    

    publisher2가 finish해야지 작동한다.

    prepend할 publisher가 언제 끝날지도 모르는데 맘대로 prepend를 끝낼 순 없으니깐

     

    Appending

    append(Output...)

    let publisher = PassthroughSubject<Int, Never>()
    
    publisher
      .append(3, 4)
      .append(5)
      .sink(receiveValue: { print($0) })
      .store(in: &subscriptions)
    
    publisher.send(1)
    publisher.send(2)
    publisher.send(completion: .finished)
    
    1
    2
    3
    4
    5
    

    prepend와 반대로 여기는 첫번째 append할 지점을 정하기 위해서 publisher가 finish해야 한다.

     

    append(Sequence)

    let publisher = [1, 2, 3].publisher
        
    publisher
      .append([4, 5])
      .append(Set([6, 7]))
      .append(stride(from: 8, to: 11, by: 2))
      .sink(receiveValue: { print($0) })
      .store(in: &subscriptions)
    
    
    1
    2
    3
    4
    5
    7
    6
    8
    10

    append(Publisher)

    let publisher1 = [1, 2].publisher
    let publisher2 = [3, 4].publisher
      
    publisher1
      .append(publisher2)
      .sink(receiveValue: { print($0) })
      .store(in: &subscriptions)
    
    1
    2
    3
    

     

    switchToLatest

    Publisher를 emit하는 Publisher가 등장한다.

    let publisher1 = PassthroughSubject<Int, Never>()
    let publisher2 = PassthroughSubject<Int, Never>()
    let publisher3 = PassthroughSubject<Int, Never>()
    
    let publishers = PassthroughSubject<PassthroughSubject<Int, Never>, Never>()
    
    publishers
      .switchToLatest()
      .sink(receiveCompletion: { _ in print("Completed!") },
            receiveValue: { print($0) })
      .store(in: &subscriptions)
    
    publishers.send(publisher1)
    publisher1.send(1)
    publisher1.send(2)
    
    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)
    
    publisher3.send(completion: .finished)
    publishers.send(completion: .finished)
    
    1
    2
    4
    5
    7
    8
    9
    Completed!

    사용자가 버튼을 탭하면 네트워크를 요청을 생성하는 시나리오를 생각해보자.

    사용자가 탭을 연타한다면??

    let url = URL(string: "https://source.unsplash.com/random")!
      
    func getImage() -> AnyPublisher<UIImage?, Never> {
        URLSession.shared
                  .dataTaskPublisher(for: url)
                  .map { data, _ in UIImage(data: data) }
                  .print("image")
                  .replaceError(with: nil)
                  .eraseToAnyPublisher()
    }
    
    let taps = PassthroughSubject<Void, Never>()
    
    taps
      .map { _ in getImage() }
      .switchToLatest()
      .sink(receiveValue: { _ in })
      .store(in: &subscriptions)
    
    taps.send()
    
    DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
      taps.send()
    }
    DispatchQueue.main.asyncAfter(deadline: .now() + 3.1) {
      taps.send()
    }
    
    image: receive subscription: (DataTaskPublisher)
    image: request unlimited
    image: receive value: (Optional(<UIImage:0x600000364120 anonymous {1080, 720}>))
    image: receive finished
    image: receive subscription: (DataTaskPublisher)
    image: request unlimited
    image: receive cancel
    image: receive subscription: (DataTaskPublisher)
    image: request unlimited
    image: receive value: (Optional(<UIImage:0x600000378d80 anonymous {1080, 1620}>))
    image: receive finished
    

    탭은 3번했지만, Fetch한 이미지는 2개뿐

     

    merge(with:)

    최대 8개까지만 머지가능

    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)
    
    publisher1.send(completion: .finished)
    publisher2.send(completion: .finished)
    
    1
    2
    3
    4
    5
    Completed

     

    combineLatest

    최대 4개까지 combine가능

    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)
    
    P1: 2, P2: a
    P1: 2, P2: b
    P1: 3, P2: b
    P1: 3, P2: c
    Completed

    zip

    SwiftUI계의 만나게해듀오. 항상 짝을 만들어 드립니다.

    let publisher1 = PassthroughSubject<Int, Never>()
    let publisher2 = PassthroughSubject<String, Never>()
    
    publisher1
        .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)
    
    P1: 1, P2: a
    P1: 2, P2: b
    P1: 3, P2: c
    Completed

    'Ray Wenderlich > Combine' 카테고리의 다른 글

    Ch4. Filtering Operators  (0) 2021.02.12
    Ch3. Transforming Operators  (0) 2021.01.27
    Ch2. Publishers & Subscribers  (0) 2021.01.27
    Ch1. Hello, Combine!  (0) 2021.01.27
Designed by Tistory.