嗨,大家好,今天明明是禮拜六卻要上班的一天(笑),今天要講講share跟shareReplay,直接開始吧。
Share是用來共享狀態,我們先看一個範例,沒加share
的狀況。
現實中,我們常會call API,並共享API回傳的結果,我們然看看以下案例,假設讓refreshSubject收到事件後,會去觸發API,會有訂閱者會去觀察 API 回傳回來的結果,我們可能會這樣寫
let refreshSubject = PublishSubject<Void>()
let result = refreshSubject.flatMapLatest { API().request().debug("Call API") }
result.debug("A").subscribe().disposed(by: disposeBag)
result.debug("B").subscribe().disposed(by: disposeBag)
refreshSubject.onNext(()) // 觸發 refresh
執行結果如下
A -> subscribed
B -> subscribed
Call API -> subscribed
Call API -> subscribed
Call API -> Event next(())
A -> Event next(())
Call API -> Event completed
Call API -> isDisposed
Call API -> Event next(())
B -> Event next(())
Call API -> Event completed
Call API -> isDisposed
可以發現 API 被呼叫兩次,也就是說每個訂閱者收到的元素都是新的,但有一種情況是,我想呼叫一次 API 就好,得到的結果讓其他觀察者共用,這時你可以在refreshSubject.flatMapLatest
後面加上.share()
let result = refreshSubject.flatMapLatest { API().request().debug("Call API") }.share()
執行結果如下
A -> subscribed
B -> subscribed
Call API -> subscribed
Call API -> Event next(())
A -> Event next(())
B -> Event next(())
Call API -> Event completed
Call API -> isDisposed
這時候 API 只會呼叫一次,並將結果共享給觀察者們。
某些情境下,我們可能會發送元素之後才訂閱,或是在不同class訂閱到,這些都會導致我們訂閱時,收不到之前發送的元素,如果是這樣的情境的話,可以使用.share(replay, scope)
,replay意思就是會緩存n個元素,這點跟之前說過的ReplaySubject很像,所以就算延遲訂閱也可以收到緩存中的元素;scope,whileConnected(預設)跟forever,當沒Observable沒有Observer時,whileConnected會清除緩存,一切重來,forever則不會。
延續上面的程式,我們改成這樣,多了一段延遲訂閱,從結果可以發現,在3秒後訂閱,還是可以收到Observable的結果
let refreshSubject = PublishSubject<Void>()
let result = refreshSubject.flatMapLatest { API().request().debug("Call API") }.share(replay: 1)
result.debug("A").subscribe().disposed(by: disposeBag)
result.debug("B").subscribe().disposed(by: disposeBag)
refreshSubject.onNext(()) // 觸發 refresh
// 1
delay(3) {
result
.debug("shareReply")
.subscribe()
.disposed(by: self.disposeBag)
}
執行結果
26:32.172: A -> subscribed
26:32.174: B -> subscribed
26:32.174: Call API -> subscribed
26:34.176: Call API -> Event next(())
26:34.176: A -> Event next(())
26:34.176: B -> Event next(())
26:34.176: Call API -> Event completed
26:34.176: Call API -> isDisposed
26:35.175: shareReply -> subscribed
26:35.175: shareReply -> Event next(())
為了能展示把Observer銷毀,我們把我們delay時間拉長到6秒,並加入一個3秒後把disposeBag清除,從結果能看到,緩存是沒有清除的。
let refreshSubject = PublishSubject<Void>()
let result = refreshSubject.flatMapLatest { API().request().debug("Call API") }.share(replay: 1, scope: .forever)
result.debug("A").subscribe().disposed(by: disposeBag)
result.debug("B").subscribe().disposed(by: disposeBag)
refreshSubject.onNext(()) // 觸發 refresh
delay(3) {
self.disposeBag = DisposeBag()
}
delay(6) {
result
.debug("shareReply")
.subscribe()
.disposed(by: self.disposeBag)
執行結果
31:13.011: A -> subscribed
31:13.013: B -> subscribed
31:13.013: Call API -> subscribed
31:15.014: Call API -> Event next(())
31:15.015: A -> Event next(())
31:15.015: B -> Event next(())
31:15.015: Call API -> Event completed
31:15.015: Call API -> isDisposed
31:16.232: A -> isDisposed
31:16.233: B -> isDisposed
31:19.014: shareReply -> subscribed
31:19.014: shareReply -> Event next(())
今天講完Share,明天會講Combining,是最後的operator,一切都快結束了,加油!