日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

RxSwift之深入解析Subject的使用和实现原理

發布時間:2024/5/21 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 信息,如下所示:

  • 使用示例如下:
let disposeBag = DisposeBag()// 創建一個PublishSubject let subject = PublishSubject<String>()// 由于當前沒有任何訂閱者,所以該信息不會被輸出到控制臺 subject.onNext("1")// 第1次訂閱subject subject.subscribe(onNext: { string inprint("第1次訂閱:", string) }, onCompleted:{print("第1次訂閱:onCompleted") }).disposed(by: disposeBag)// 當前有1個訂閱,則該信息會被輸出到控制臺 subject.onNext("2")// 第2次訂閱subject subject.subscribe(onNext: { string inprint("第2次訂閱:", string) }, onCompleted:{print("第2次訂閱:onCompleted") }).disposed(by: disposeBag)// 當前有2個訂閱,則該信息會輸出到控制臺 subject.onNext("3")// subject結束 subject.onCompleted()// subject完成后會發出.next事件 subject.onNext("4")// subject完成后它的所有訂閱(包括結束后的訂閱),都能收到subject的.completed事件 subject.subscribe(onNext: { string inprint("第3次訂閱:", string) }, onCompleted:{print("第3次訂閱:onCompleted") }).disposed(by: disposeBag)
  • 運行結果如下:
1次訂閱: 21次訂閱: 32次訂閱: 31次訂閱:onCompleted 第2次訂閱:onCompleted 第3次訂閱:onCompleted

三、AsyncSubject

  • AsyncSubject 只發送由源 Observable 發送的最后一個事件,并且只在源 Observable 完成之后(如果源 Observable 沒有發送任何值,AsyncSubject 也不會發送任何值):

  • AsyncSubject 會發送相同的值給所有 observer。但是,如果源 Observable 被 error 中斷了發送,AsyncSubject 便不會發送任何事件,而是會發送從源 Observable 傳來的 error 提示:

  • 使用示例:
let disposeBag = DisposeBag() // 創建序列 let asynSub = AsyncSubject<Int>.init() // 發送信號 asynSub.onNext(1) asynSub.onNext(2) // 訂閱序列 asynSub.subscribe{ print("訂閱到:",$0)}.disposed(by: disposeBag) // 再次發送 asynSub.onNext(3) asynSub.onNext(4) // asynSub.onError(NSError.init(domain: "dw", code: 10086, userInfo: nil)) asynSub.onCompleted()
  • 運行結果如下:
訂閱到: next(4) 訂閱到: completed

四、BehaviorSubject

  • 當一個 observer 訂閱一個 BehaviorSubject,它就開始發送最近由源 Observable 發送的事件(或者是還沒有被發送的種子值/默認值),然后繼續發送從源 Observable 接收到的其它事件。如下所示:

  • 如果源 Observable 被一個 error 中斷,那么 BehaviorSubject 不會發送事件給后續的 observer,但會傳遞給它們 error 的信息。如下所示:

  • 使用示例:
let disposeBag = DisposeBag()// 創建一個BehaviorSubject let subject = BehaviorSubject(value: "1")// 第1次訂閱subject subject.subscribe { event inprint("第1次訂閱:", event) }.disposed(by: disposeBag)// 發送next事件 subject.onNext("2")// 發送error事件 subject.onError(NSError(domain: "dw", code: 0, userInfo: nil))// 第2次訂閱subject subject.subscribe { event inprint("第2次訂閱:", event) }.disposed(by: disposeBag)
  • 運行結果如下:
1次訂閱: next(1)1次訂閱: next(2)1次訂閱: error(Error Domain=dw Code=0 "(null)")2次訂閱: error(Error Domain=dw Code=0 "(null)")

五、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(如果有):

  • 使用示例:
let disposeBag = DisposeBag()// 創建一個bufferSize為2的ReplaySubject let subject = ReplaySubject<String>.create(bufferSize: 2)// 連續發送3個next事件 subject.onNext("1") subject.onNext("2") subject.onNext("3")// 第1次訂閱subject subject.subscribe { event inprint("第1次訂閱:", event) }.disposed(by: disposeBag)// 再發送1個next事件 subject.onNext("4")// 第2次訂閱subject subject.subscribe { event inprint("第2次訂閱:", event) }.disposed(by: disposeBag)// 讓subject結束 subject.onCompleted()// 第3次訂閱subject subject.subscribe { event inprint("第3次訂閱:", event) }.disposed(by: disposeBag)
  • 運行結果如下:
1次訂閱: next(2)1次訂閱: next(3)1次訂閱: next(4)2次訂閱: next(3)2次訂閱: next(4)1次訂閱: completed 第2次訂閱: completed 第3次訂閱: next(3)3次訂閱: next(4)3次訂閱: completed

六、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 類型就能訂閱它。
  • 使用示例:
let disposeBag = DisposeBag()// 創建一個初始值為1的Variable let variable = Variable("1")// 修改value值 variable.value = "2"// 第1次訂閱 variable.asObservable().subscribe {print("第1次訂閱:", $0) }.disposed(by: disposeBag)// 修改value值 variable.value = "3"// 第2次訂閱 variable.asObservable().subscribe {print("第2次訂閱:", $0) }.disposed(by: disposeBag)// 修改value值 variable.value = "4"
  • 運行結果:
1次訂閱: next(2)1次訂閱: next(3)2次訂閱: next(3)1次訂閱: next(4)2次訂閱: next(4)1次訂閱: completed 第2次訂閱: completed
  • Variable 雖然被廢棄了,但是由于 Variable 的靈活性,因此在開發里面應用非常之多。

七、BehaviorRelay

  • BehaviorRelay 會替換原來的 Variable,儲存一個信號,并且可以隨時訂閱響應,但響應發送的時候要注意 behaviorR.accept(20):
let disposeBag = DisposeBag() let behaviorRelay = BehaviorRelay(value: 100) behaviorRelay.subscribe(onNext: { (num) inprint(num) .disposed(by: disposeBag) print("打印:\(behaviorRelay.value)")behaviorRelay.accept(1000)

八、Subject 原理分析

① SubjectType

  • SubjectType 繼承自 ObservableType,具有序列特性,并且關聯觀察者類型,具備觀察者類型的能力,如下:
public protocol SubjectType : ObservableType {// 關聯觀察者類型,具備觀察者類型的能力associatedtype SubjectObserverType : ObserverTypefunc asObserver() -> SubjectObserverType }
  • 現有如下實例 subject:
let disposeBag = DisposeBag() // 初始化序列 let publishSub = PublishSubject<Int>() // 發送響應序列 publishSub.onNext(1) // 訂閱序列 publishSub.subscribe { print("訂閱到:",$0)}.disposed(by: disposeBag) // 再次發送響應 publishSub.onNext(2) publishSub.onNext(3)
  • 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)。
mutating func removeKey(_ key: BagKey) -> T? {if _key0 == key {_key0 = nillet value = _value0!_value0 = nilreturn value}if let existingObject = _dictionary?.removeValue(forKey: key) {return existingObject}for i in 0 ..< _pairs.count where _pairs[i].key == key {let value = _pairs[i].value_pairs.remove(at: i)return value}return nil }
  • 遍歷通過 key 獲取響應 bag 中的 value,執行集合移除,因為沒有相應持有關系,達到自動釋放銷毀。

③ 發送信號流程

public func on(_ event: Event<Element>) {dispatch(self._synchronized_on(event), event) }
  • 這里調用了 dispatch 函數,傳了兩個參數:self._synchronized_on(event) 和 event,查看 dispatch 函數源碼:
func dispatch<E>(_ bag: Bag) {bag._value0?(event)if bag._onlyFastPath {return}let pairs = bag._pairsfor i in 0 ..< pairs.count {pairs[i].value(event)}if let dictionary = bag._dictionary {for element in dictionary.values {element(event)}} }
  • bag._value0?(event) 首先執行事件的回調,然后判斷 bag._onlyFastPath 的情況,默認會開啟快速通道,如果是開啟慢速通道,需要從剛剛添加進 bag 包里面的匹配,挨個進行 pairs[i].value(event) 外界事件回調,然后拿回外界封裝的閉包的閉包調用 :element(event)。
func _synchronized_on(_ event: Event<E>) -> Observers {self._lock.lock(); defer { self._lock.unlock() }switch event {case .next:if self._isDisposed || self._stopped {return Observers()}return self._observerscase .completed, .error:if self._stoppedEvent == nil {self._stoppedEvent = eventself._stopped = truelet observers = self._observersself._observers.removeAll()return observers}return Observers()} }
  • 如果 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的使用和实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。