--- title: 'RxSwift Share() vs Combine Share()' tags: SwiftUI disqus: hackmd --- **目錄:** [TOC] ## share() ### PublishSubject ```swift= let refreshSubject = PublishSubject<Int>() let result = refreshSubject.debug("result").share() refreshSubject.onNext(0) // 觸發 refresh result.debug("shit A").subscribe().disposed(by: disposeBag) refreshSubject.onNext(1) // 觸發 refresh result.debug("shit B").subscribe().disposed(by: disposeBag) refreshSubject.onNext(2) // 觸發 refresh // 1 DispatchQueue.main.asyncAfter(deadline: .now() + 1) { self.disposeBag = DisposeBag() } DispatchQueue.main.asyncAfter(deadline: .now() + 2) { result .debug("shit C") .subscribe() .disposed(by: self.disposeBag) result .debug("shit D") .subscribe() .disposed(by: self.disposeBag) } ``` #### RxSwift 只會接收到訂閱之後發送的元素(例如:A接不到next(0),B接不到next(1)) ``` 2024-09-09 13:46:02.069: shit A -> subscribed 2024-09-09 13:46:02.069: result -> subscribed 2024-09-09 13:46:02.069: result -> Event next(1) 2024-09-09 13:46:02.069: shit A -> Event next(1) 2024-09-09 13:46:02.069: shit B -> subscribed 2024-09-09 13:46:02.070: result -> Event next(2) 2024-09-09 13:46:02.070: shit A -> Event next(2) 2024-09-09 13:46:02.070: shit B -> Event next(2) 2024-09-09 13:46:03.117: shit A -> isDisposed 2024-09-09 13:46:03.117: shit B -> isDisposed 2024-09-09 13:46:03.117: result -> isDisposed 2024-09-09 13:46:04.169: shit C -> subscribed 2024-09-09 13:46:04.169: result -> subscribed 2024-09-09 13:46:04.170: shit D -> subscribed ``` #### Combine 與RxSwift一致 ``` shit A: receive subscription: (Multicast) shit A: request unlimited shit A: receive value: (1) shit B: receive subscription: (Multicast) shit B: request unlimited shit A: receive value: (2) shit B: receive value: (2) shit B: receive cancel shit A: receive cancel shit C: receive subscription: (Multicast) shit C: request unlimited shit D: receive subscription: (Multicast) shit D: request unlimited ``` ### BehaviorSubject ```swift= let refreshSubject = BehaviorSubject<Int>(value: -1) ``` #### RxSwift A 訂閱後會先收到 BehaviorSubject 帶給它的 next(0) 而 B 訂閱後卻不會收到 BehaviorSubject 目前的 next(1) 並且在全部清除重新訂閱之後,C 會跟 A 一樣先收到 BehaviorSubject 目前的元素 ``` 2024-09-09 13:37:49.676: shit A -> subscribed 2024-09-09 13:37:49.676: result -> subscribed 2024-09-09 13:37:49.677: result -> Event next(0) 2024-09-09 13:37:49.677: shit A -> Event next(0) 2024-09-09 13:37:49.677: result -> Event next(1) 2024-09-09 13:37:49.677: shit A -> Event next(1) 2024-09-09 13:37:49.677: shit B -> subscribed 2024-09-09 13:37:49.677: result -> Event next(2) 2024-09-09 13:37:49.677: shit A -> Event next(2) 2024-09-09 13:37:49.677: shit B -> Event next(2) 2024-09-09 13:37:50.722: shit A -> isDisposed 2024-09-09 13:37:50.722: shit B -> isDisposed 2024-09-09 13:37:50.722: result -> isDisposed 2024-09-09 13:37:51.772: shit C -> subscribed 2024-09-09 13:37:51.775: result -> subscribed 2024-09-09 13:37:51.776: result -> Event next(2) 2024-09-09 13:37:51.777: shit C -> Event next(2) 2024-09-09 13:37:51.777: shit D -> subscribed ``` #### Combine 與RxSwift一致 ``` shit A: receive subscription: (Multicast) shit A: request unlimited shit A: receive value: (0) shit A: receive value: (1) shit B: receive subscription: (Multicast) shit B: request unlimited shit B: receive value: (2) shit A: receive value: (2) shit B: receive cancel shit A: receive cancel shit C: receive subscription: (Multicast) shit C: request unlimited shit C: receive value: (2) shit D: receive subscription: (Multicast) shit D: request unlimited ``` ## Share(replay: 1) ### PublishSubject ``` let refreshSubject = PublishSubject<Int>() let result = refreshSubject.share(replay: 1) ``` #### RxSwift 因為 (replay: 1) 的關係,B會在訂閱後且 refreshSubject 未發送 onNext 之前先接受到目前的一個元素 ``` 2024-09-09 11:11:09.536: shit A -> subscribed 2024-09-09 11:11:09.539: shit A -> Event next(1) 2024-09-09 11:11:09.539: shit B -> subscribed 2024-09-09 11:11:09.540: shit B -> Event next(1) 2024-09-09 11:11:09.540: shit A -> Event next(2) 2024-09-09 11:11:09.540: shit B -> Event next(2) 2024-09-09 11:11:10.590: shit A -> isDisposed 2024-09-09 11:11:10.590: shit B -> isDisposed 2024-09-09 11:11:11.637: shit C -> subscribed 2024-09-09 11:11:11.637: shit D -> subscribed ``` #### Combine 這邊就開始不一樣了哦,有沒有發現解除綁定後,重新綁定的 C、D 還是可以接收到 refreshSubject 的第一個元素? 這是因為Combine Share()的預設並不是.whileConnected,而是.forever ``` shit A: receive subscription: (Multicast) shit A: request unlimited shit A: receive value: (1) shit B: receive subscription: (Multicast) shit B: request unlimited shit B: receive value: (1) shit A: receive value: (2) shit B: receive value: (2) shit B: receive cancel shit A: receive cancel shit C: receive subscription: (Multicast) shit C: request unlimited shit C: receive value: (2) shit D: receive subscription: (Multicast) shit D: request unlimited shit D: receive value: (2) ``` #### .whileConnected vs .forever .whileConnected (在 RxSwift 中預設) • 當所有訂閱者取消訂閱時,原始的序列會自動斷開,並且當有新的訂閱者時,會重新啟動序列。 • 這類似於 “引用計數”(reference counting)行為,當沒有訂閱者時,資源會釋放,而當新的訂閱者出現時,會重新創建。 • 行為: 當所有的訂閱者斷開時,源會被中斷,並且新訂閱者會重啟流。 .forever (在 Combine 中預設) • 當第一個訂閱者訂閱時,原始序列會被啟動,並且即使所有訂閱者都取消訂閱,原始序列依然保持連接並持續運行。 • 資源只會在序列自然完成或發生錯誤時釋放。 • 行為: 當第一個訂閱者訂閱後,無論後面有多少訂閱者取消或重新訂閱,源都保持活躍,直到它自然完成或出現錯誤。 所以這邊把 Combine 改成 .whileConnected 就會跟 RxSwift 一致了。 ### BehaviorSubject ```swift= let refreshSubject = BehaviorSubject<Int>(value: -1) let result = refreshSubject.share(replay: 1) ``` #### RxSwift A 訂閱後會先收到 BehaviorSubject 帶給它的 next(0) 而 B 也可以接收到 result (replay: 1) 目前的元素 然後 C 因為 BehaviorSubject 的關係,本身就會接收到最新的元素 至於 D 則是因為 result (replay: 1) 的關係才接受到元素的 ``` 2024-09-09 13:33:09.719: shit A -> subscribed 2024-09-09 13:33:09.719: result -> subscribed 2024-09-09 13:33:09.720: result -> Event next(0) 2024-09-09 13:33:09.720: shit A -> Event next(0) 2024-09-09 13:33:09.720: result -> Event next(1) 2024-09-09 13:33:09.720: shit A -> Event next(1) 2024-09-09 13:33:09.720: shit B -> subscribed 2024-09-09 13:33:09.720: shit B -> Event next(1) 2024-09-09 13:33:09.720: result -> Event next(2) 2024-09-09 13:33:09.720: shit A -> Event next(2) 2024-09-09 13:33:09.721: shit B -> Event next(2) 2024-09-09 13:33:10.731: shit A -> isDisposed 2024-09-09 13:33:10.731: shit B -> isDisposed 2024-09-09 13:33:10.731: result -> isDisposed 2024-09-09 13:33:11.730: shit C -> subscribed 2024-09-09 13:33:11.731: result -> subscribed 2024-09-09 13:33:11.731: result -> Event next(2) 2024-09-09 13:33:11.731: shit C -> Event next(2) 2024-09-09 13:33:11.731: shit D -> subscribed 2024-09-09 13:33:11.731: shit D -> Event next(2) ``` ## Share(replay: 1, scope: .forever) ### PublishSubject ```swift= let refreshSubject = PublishSubject<Int>() let result = refreshSubject.debug("result").share(replay: 1, scope: .forever) ``` 與 .whileConnect 不同的是,因為 .forever 不會回收的關係,所以 C、D 會接收到 next(2) ``` 2024-09-09 13:57:14.768: shit A -> subscribed 2024-09-09 13:57:14.769: result -> subscribed 2024-09-09 13:57:14.770: result -> Event next(1) 2024-09-09 13:57:14.770: shit A -> Event next(1) 2024-09-09 13:57:14.770: shit B -> subscribed 2024-09-09 13:57:14.770: shit B -> Event next(1) 2024-09-09 13:57:14.770: result -> Event next(2) 2024-09-09 13:57:14.770: shit A -> Event next(2) 2024-09-09 13:57:14.770: shit B -> Event next(2) 2024-09-09 13:57:15.820: shit A -> isDisposed 2024-09-09 13:57:15.820: shit B -> isDisposed 2024-09-09 13:57:15.820: result -> isDisposed 2024-09-09 13:57:16.869: shit C -> subscribed 2024-09-09 13:57:16.869: shit C -> Event next(2) 2024-09-09 13:57:16.869: result -> subscribed 2024-09-09 13:57:16.869: shit D -> subscribed 2024-09-09 13:57:16.869: shit D -> Event next(2) ``` ### BehaviorSubject ```swift= let refreshSubject = BehaviorSubject<Int>(value: -1) let result = refreshSubject.debug("result").share(replay: 1, scope: .forever) ``` #### RxSwift 與 .whileConnect 的差別就是 C 重新訂閱時,因為 .forever 不會回收的關係,它本身已經有元素了,所以會先接受到一個 next(2),之後 result 又打出一個 BehaviorSubject 的 next(2),才會導致出現兩次 ``` 2024-09-09 13:53:10.532: shit A -> subscribed 2024-09-09 13:53:10.533: result -> subscribed 2024-09-09 13:53:10.534: result -> Event next(0) 2024-09-09 13:53:10.534: shit A -> Event next(0) 2024-09-09 13:53:10.534: result -> Event next(1) 2024-09-09 13:53:10.534: shit A -> Event next(1) 2024-09-09 13:53:10.534: shit B -> subscribed 2024-09-09 13:53:10.534: shit B -> Event next(1) 2024-09-09 13:53:10.534: result -> Event next(2) 2024-09-09 13:53:10.535: shit A -> Event next(2) 2024-09-09 13:53:10.535: shit B -> Event next(2) 2024-09-09 13:53:11.573: shit A -> isDisposed 2024-09-09 13:53:11.573: shit B -> isDisposed 2024-09-09 13:53:11.573: result -> isDisposed 2024-09-09 13:53:12.573: shit C -> subscribed 2024-09-09 13:53:12.574: shit C -> Event next(2) 2024-09-09 13:53:12.574: result -> subscribed 2024-09-09 13:53:12.574: result -> Event next(2) 2024-09-09 13:53:12.574: shit C -> Event next(2) 2024-09-09 13:53:12.574: shit D -> subscribed 2024-09-09 13:53:12.574: shit D -> Event next(2) ```
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up