RxSwift之深入解析Subject的使用和实现原理
生活随笔
收集整理的這篇文章主要介紹了
RxSwift之深入解析Subject的使用和实现原理
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一、Subject
- RxSwift 的核心邏輯 Observable 不具備發送事件的能力,創建一個 Observable 的時候就要預先將要發出的數據都準備好,等到有人訂閱它時再將數據通過 Event 發出去。但有時希望 Observable 在運行時能動態地獲得或者說產生一個新的數據,再通過 Event 發送出去。比如,訂閱一個輸入框的輸入內容,當用戶每輸入一個字符之后,輸入框關聯的 Observable 就會發出一個帶有輸入內容的 Event,通知給所有訂閱者。為此,RxSwift 提供了一種可以發送事件又可以訂閱事件值的對象,它就是 Subject。
- Subject 既是訂閱者,也是 Observable:它是訂閱者,是因為能夠動態地接收新的值;它是 Observable,是因為當 Subjects 有了新的值之后,就會通過 Event 將新值發出給它的所有訂閱者。
- Subject 常用的方法:
-
- onNext( : ):是 on(.next( : )) 的簡寫,該方法相當于 subject 接收到一個.next 事件;
-
- onError( : ):是 on(.error( : )) 的簡寫,該方法相當于 subject 接收到一個 .error 事件;
-
- onCompleted():是 on(.completed) 的簡寫,該方法相當于 subject 接收到一個 .completed 事件。
二、PublishSubject
- PublishSubject 不需要初始值就能創建,它的訂閱者從開始訂閱的時間點起,可以收到訂閱后 Subject 發出的新 Event,而不會收到它們在訂閱前已發出的 Event,即 PublishSubject 僅僅發送在訂閱之后由源 Observable 發送的數據。
- 如下所示,最上面是 PublishSubject,下面分別表示兩個新的訂閱,它們訂閱的時間點不同,可以發現 PublishSubject 的訂閱者只能收到它們訂閱后的 Event:
- PublishSubject 一旦被建立就會立刻開始發送事件(除非采取方法去阻止它),這種機制有丟失事件的風險,因為在 Subject 被創建和被監聽之間有一定的時間間隔,如果想保證所有的事件都可以被監聽到的話,可以有兩種方法:
-
- 第一種方法是使用 Create 方法(在發送之前檢查是否所有 observer 已經訂閱);
-
- 第二種方法是可以使用 ReplaySubject。
- 如果源 Observable 被一個 error 中斷,PublishSubject 將不會發送任何事件給后續的 observer,但是它會傳遞 error 信息,如下所示:
- 使用示例如下:
- 運行結果如下:
三、AsyncSubject
- AsyncSubject 只發送由源 Observable 發送的最后一個事件,并且只在源 Observable 完成之后(如果源 Observable 沒有發送任何值,AsyncSubject 也不會發送任何值):
- AsyncSubject 會發送相同的值給所有 observer。但是,如果源 Observable 被 error 中斷了發送,AsyncSubject 便不會發送任何事件,而是會發送從源 Observable 傳來的 error 提示:
- 使用示例:
- 運行結果如下:
四、BehaviorSubject
- 當一個 observer 訂閱一個 BehaviorSubject,它就開始發送最近由源 Observable 發送的事件(或者是還沒有被發送的種子值/默認值),然后繼續發送從源 Observable 接收到的其它事件。如下所示:
- 如果源 Observable 被一個 error 中斷,那么 BehaviorSubject 不會發送事件給后續的 observer,但會傳遞給它們 error 的信息。如下所示:
- 使用示例:
- 運行結果如下:
五、ReplaySubject
- ReplaySubject 在創建時候需要設置一個 bufferSize,表示它對于它發送過的 event 的緩存個數。比如一個 ReplaySubject 的 bufferSize 設置為 2,它發出了 3 個 .next 的 event,那么它會將后兩個(最近的兩個)event 給緩存起來。此時如果有一個 subscriber 訂閱了這個 ReplaySubject,那么這個 subscriber 就會立即收到前面緩存的兩個.next 的 event。
- 如果一個 subscriber 訂閱已經結束的 ReplaySubject,除了會收到緩存的 .next 的 event外,還會收到那個終結的 .error 或者 .complete 的event。
- 如下所示,最上面是 ReplaySubject(bufferSize 設為為 2),下面分別表示兩個新的訂閱,它們訂閱的時間點不同,可以發現 ReplaySubject 的訂閱者一開始就能收到 ReplaySubject 之前發出的兩個 Event(如果有):
- 使用示例:
- 運行結果如下:
六、Variable
- Variable 其實就是對 BehaviorSubject 的封裝,所以它也必須要通過一個默認的初始值進行創建,它具有 BehaviorSubject 的功能,能夠向它的訂閱者發出上一個 event 以及之后新創建的 event。
- 不同的是,Variable 還會把當前發出的值保存為自己的狀態,同時它會在銷毀時自動發送 .complete 的 event,不需要也不能手動給 Variables 發送 completed 或者 error 事件來結束它。
- 簡單地說,就是 Variable 有一個 value 屬性,改變這個 value 屬性的值就相當于調用一般 Subjects 的 onNext() 方法,而這個最新的 onNext() 的值就被保存在 value 屬性里,直到再次修改它。
- Variables 本身沒有 subscribe() 方法,但是所有 Subjects 都有一個 asObservable() 方法,可以使用這個方法返回這個 Variable 的 Observable 類型,拿到這個 Observable 類型就能訂閱它。
- 使用示例:
- 運行結果:
- Variable 雖然被廢棄了,但是由于 Variable 的靈活性,因此在開發里面應用非常之多。
七、BehaviorRelay
- BehaviorRelay 會替換原來的 Variable,儲存一個信號,并且可以隨時訂閱響應,但響應發送的時候要注意 behaviorR.accept(20):
八、Subject 原理分析
① SubjectType
- SubjectType 繼承自 ObservableType,具有序列特性,并且關聯觀察者類型,具備觀察者類型的能力,如下:
- 現有如下實例 subject:
- PublishSubject 很明顯能夠訂閱信號(序列最基本的能力),并且能夠發送響應,又是觀察者的能力。
② 訂閱響應流程
public override func subscribe -> Disposable {self._lock.lock()let subscription = self._synchronized_subscribe(observer)self._lock.unlock()return subscription }func _synchronized_subscribe -> Disposable {............let key = self._observers.insert(observer.on)return SubscriptionDisposable(owner: self, key: key) }- self._observers.insert(observer.on): 通過一個集合添加進去所有的訂閱事件,很明顯在合適的地方一次性全部執行。其中也返回這次訂閱的銷毀者,方便執行之后的工作:synchronizedUnsubscribe->self._observers.removeKey(disposeKey)。
- 遍歷通過 key 獲取響應 bag 中的 value,執行集合移除,因為沒有相應持有關系,達到自動釋放銷毀。
③ 發送信號流程
public func on(_ event: Event<Element>) {dispatch(self._synchronized_on(event), event) }- 這里調用了 dispatch 函數,傳了兩個參數:self._synchronized_on(event) 和 event,查看 dispatch 函數源碼:
- bag._value0?(event) 首先執行事件的回調,然后判斷 bag._onlyFastPath 的情況,默認會開啟快速通道,如果是開啟慢速通道,需要從剛剛添加進 bag 包里面的匹配,挨個進行 pairs[i].value(event) 外界事件回調,然后拿回外界封裝的閉包的閉包調用 :element(event)。
- 如果 self._isDisposed || self._stopped 成立,就會返回一個空的集合,也就沒有序列的響應。在 .completed, .error 都會改變狀態 self._stopped = true,也就是說序列完成或者錯誤之后都無法再次響應。在.completed, .error 還會移除添加在集合里面的內容。
- Subject 流程圖如下(Subject 把訂閱流程和響應流程都內部實現,所以沒有必要引入 sink):
④ Subject 對比
- PublishSubject、BehaviorSubject、ReplaySubject、AsyncSubject、Variable,它們之間既有各自的特點,也有相同之處:
-
- 首先它們都是 Observable,它們的訂閱者都能收到它們發出的新的 Event;
-
- 直到 Subject 發出 .complete 或者 .error 的 Event 后,該 Subject 便終結,同時它也就不會再發出 .next 事件;
-
- 對于那些在 Subject 終結后再訂閱它的訂閱者,也能收到 subject 發出的一條 .complete 或 .error 的 event,告訴新的訂閱者它已經終結。
- 它們之間最大的區別只是在于:當一個新的訂閱者剛訂閱它的時候,能不能收到 Subject 以前發出過的舊 Event,如果能的話又能收到多少個 Event。
總結
以上是生活随笔為你收集整理的RxSwift之深入解析Subject的使用和实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RxSwift之深入解析map操作符的底
- 下一篇: 【数据结构与算法】之深入解析“汉诺塔问题