[회고] 신입 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가 값을 한번에 받는다.