[회고] 신입 iOS 개발자가 되기까지 feat. 카카오 자세히보기

🍎 Apple/Combine & Rx

[Combine] share, multicast

inu 2022. 1. 13. 18:20
반응형

share

  • 하나의 upstream publisher의 output을 여러 subscriber들이 공유할 수 있도록 해준다.

Example 1

guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else {
    fatalError("Invalid URL")
}

let request = URLSession.shared.dataTaskPublisher(for: url).map(\.data).print().share()

let subscription1 = request.sink(receiveCompletion: { _ in }, receiveValue: {
    print("Subscription 1")
    print($0)
})

let subscription2 = request.sink(receiveCompletion: { _ in }, receiveValue: {
    print("Subscription 2")
    print($0)
})

Output 1

receive subscription: (DataTaskPublisher)
request unlimited
receive value: (27520 bytes)
Subscription 1
27520 bytes
Subscription 2
27520 bytes
receive finished

  • Output을 공유하기 때문에 요청은 한번만 수행된다.

Example 2

let pub = (1...3).publisher
    .delay(for: 1, scheduler: DispatchQueue.main)
    .map( { _ in return Int.random(in: 0...100) } )
    .print("Random")
    .share()

let cancellable1 = pub
    .sink { print ("Stream 1 received: \($0)")}
let cancellable2 = pub
    .sink { print ("Stream 2 received: \($0)")}

Output 2

Random: request unlimited
Random: receive value: (18)
Stream 1 received: 18
Stream 2 received: 18
Random: receive value: (94)
Stream 1 received: 94
Stream 2 received: 94
Random: receive value: (10)
Stream 1 received: 10
Stream 2 received: 10
Random: receive finished

  • Output을 공유하기 때문에 일정한 랜덤값을 받는다. (공유하지 않는다면 각각 다른 랜덤값을 받아올 것이다.)

multicast

  • 하나의 Output을 전달하는 subject를 여러 subscriber에게 제공한다.
  • 즉, 각각 subscriber들이 값을 전달받는 용도의 subject를 갖게되면서 이를 통해 하나의 전달값을 동시에 받아올 수 있게 되는 것이다.
  • 여러 downstream subscriber가 있어도, publisher는 한번만 값을 발행한다. 따라서 값을 발행하는 과정에서 부하가 큰 작업(네크워크 요청 등)에 유용하게 사용할 수 있다.
  • 이렇게 publisher는 ConnectablePublisher이기 때문에 connect() 메서드를 수행해야 값 발행을 시작한다.
  • multicast(_:) 는 클로저를 받아 각각의 Subject에게 다른 Subject를 제공하지만, multicast(subject:)는 하나의 단일 Subject를 제공한다는 것이 다르다.

Example

guard let url = URL(string: "https://jsonplaceholder.typicode.com/posts") else {
    fatalError("Invalid URL")
}

let subject = PassthroughSubject<Data, URLError>()

let request = URLSession.shared.dataTaskPublisher(for: url).map(\.data).print().multicast(subject: subject)

let subscription1 = request.sink(receiveCompletion: { _ in }, receiveValue: {
    print("Subscription 1")
    print($0)
})

let subscription2 = request.sink(receiveCompletion: { _ in }, receiveValue: {
    print("Subscription 2")
    print($0)
})


let subscription3 = request.sink(receiveCompletion: { _ in }, receiveValue: {
    print("Subscription 3")
    print($0)
})

let cacellalbe = request.connect()

Output

receive subscription: (DataTaskPublisher)
request unlimited
receive value: (27520 bytes)
Subscription 2
27520 bytes
Subscription 3
27520 bytes
Subscription 1
27520 bytes
receive finished

  • 각각의 subscriber가 한번의 작업만으로 값들을 받아옴을 알 수 있다.
  • cf. 물론 값 전달용도로 생성한 subject에도 값을 발행할 수 있다. 이 경우에도 모든 subscriber가 값을 한번에 받는다.
반응형