subscribe와 receive
- 둘 다
Combine
에서Scheduler
를 정하는 인스턴스 메소드이다. 그런데 테스트해보니 둘이 내뱉는 결과가 아예 달랐다.// 테스트를 위한 코드 var cancellable = Set<AnyCancellable>() let publisher = [1, 2, 3].publisher publisher .map{ num in print("map: \(Thread.current)") return num } .subscribe(on: DispatchQueue.global()) .sink(receiveCompletion: { completion in print("completion") }, receiveValue: { num in print("\(num): \(Thread.current)") }) .store(in: &cancellable)
- subscrbe로 받은 데이터는 모두 같은 스레드에서 실행되지만 receive로 받은 요소들은 제각각 실행된다.
- 참고로 위의 해당 코드를 실행시켜보면 실제로는 sink에서 3번째 print가 뜨기 전에 finished된다. subscribe와 receive의 차이를 통해 그 이유도 추측해볼 수 있을 것 같다.
subscribe와 receive의 정의
- subscribe : 구독과 취소, 요청에 대한 작업을 수행할 스케쥴러를 지정한다.
- receive : publisher로 부터 방출하는 요소를 받을 스케쥴러를 지정한다.
→ 뭔차인지 모르겠다.
subscribe vs receive
- Publisher에서 주석으로 작성된 정의를 보니 조금 더 이해할 수 있었다.
- subscribe: 업스트림이 요청받을 스케쥴러를 변경한다.
- receive: 업스트림으로부터 전달받은 요소를 다운스트림에 전달할 스케쥴러를 변경한다. → Combine에서 Publisher와 Subscriber가 데이터를 다루는 과정을 볼 때에 그림의 말풍선의 위치에서 스케쥴러가 변경이 되는게 아닌가 싶다.
subscirbe(on: DispatchQueue.global())
을 통해 요청한 데이터는 이미 스레드의 위치를 결정하고 요청했기 때문에 sink를 통해 받는 데이터들의 스레드 위치가 똑같다.
receive(on: DispatchQueue.global())
를 통해 요청한 데이터는 GCD가 해당 요소마다 스레드를 배정하기 때문에 sink를 통해 받는 데이터들의 스레드 위치가 차이가 있다.
→ 위의 테스트 코드에서는 receive를 통해 받으면 GCD가 스레드를 배정하고, 작업을 처리하는 속도보다 publisher가 마지막 요소를 방출하고 finished를 때리는 속도가 빨라 몇몇 누락되는 요소들이 생긴게 아닌가 싶다. → 때문에 publisher 를 PassthroughSubject로 만들어 send로 값을 주입하면 생략되는 문제가 해결된다.
Reference
Uploaded by N2T