前一篇文章講述 RxSwift 框架中最重要的類 Observable<T>
,但是其局限性只能作為被訂閱者被動接收信號并響應(yīng)事件。項(xiàng)目中避免不了主動發(fā)出信號操作的情況,這時(shí)就需要 Subject
類來完成。與之前RAC框架中的 Subject 類功能非常相似,既能攻也能受啃奴,是不僅可以成為可觀察對象被動接受事件潭陪,還可以成為觀察者主動發(fā)送事件。
Subject 其訂閱者也是 Observable
最蕾,首先可以動態(tài)地接受新值依溯,其次當(dāng) subject 值更新時(shí),會通過 event 把新值發(fā)送給所有的訂閱者瘟则。
在 RxSwift 框架中黎炉,提供了四種類型的 subject,首先要了解的一點(diǎn)就是提供的四種 subject 創(chuàng)建方式最主要的區(qū)別:當(dāng)一個(gè)新的訂閱者訂閱到subject對象時(shí)醋拧,能否收到 subject 以前發(fā)出過的舊 event慷嗜,如果能,接收的數(shù)量又有不同丹壕。
-
PublishSubject
最普通的 subject 庆械,不需要初始值就可以創(chuàng)建,而且從訂閱者開始訂閱的時(shí)間點(diǎn)起菌赖,可以收到 subject 發(fā)出的新 event缭乘,而不會收到在訂閱前已發(fā)出的 event -
BehaviorSubject
當(dāng)訂閱者訂閱 subject 時(shí),會立即收到 BehaviorSubject 上一個(gè)發(fā)出的 event琉用,之后與 PublishSubject 功能相同 -
ReplaySubject
除了包含 PublishSubject 的功能堕绩,還可以手動設(shè)置訂閱者接收到舊的 event 個(gè)數(shù)。因此邑时,在使用時(shí)必須在創(chuàng)建時(shí)設(shè)置 bufferSize奴紧,表示將會返回給訂閱者對應(yīng)個(gè)數(shù)最近緩存的舊 event
(注:若一個(gè)訂閱者去訂閱已經(jīng)結(jié)束的 ReplaySubject ,除了會收到緩存的 .next 的 event之外晶丘,還會收到終結(jié)該 ReplaySubject 的 .error 或 .completed 的event)
在實(shí)際開發(fā)過程中绰寞,ReplaySubject 緩存機(jī)制使用了數(shù)組結(jié)構(gòu)
,所以當(dāng)有大量 ReplaySubject 對象時(shí)可能導(dǎo)致內(nèi)存暴增。另外滤钱,如果緩存對象是圖片觉壶、視頻等極耗內(nèi)存的資源時(shí)也可能導(dǎo)致內(nèi)存問題。所以 ReplaySubject 不可濫用且緩存區(qū)大小必須合理進(jìn)行設(shè)置件缸,必要時(shí)可手動進(jìn)行釋放管理 -
Variable
本身是對 BehaviorSubject 封裝铜靶,創(chuàng)建時(shí)也必須設(shè)置一個(gè)默認(rèn)值。繼承自 BehaviorSubject 他炊,那么就能向訂閱者發(fā)出上一個(gè) event 與新的 event争剿。與 BehaviorSubject 不同的是,Variable還會把當(dāng)前發(fā)出的值保存為自己的狀態(tài)痊末,同時(shí)在銷毀時(shí)自動發(fā)送 .completed event蚕苇,不需要也不能手動給 Variable 發(fā)送終結(jié)事件 .completed 或 .error 來終結(jié)。
換個(gè)方式理解凿叠,Variable 有一個(gè) value 屬性涩笤,當(dāng)改變 value 屬性的值時(shí)就相當(dāng)于調(diào)用一般 Subjects 的 onNext() 方法,而這個(gè)最新的 onNext() 的值就被保存在 value 屬性里盒件,直到再次修改 value
(注:Variable 本身沒有提供 subscribe() 方法蹬碧,但是所有 Subjects 都有一個(gè) asObservable() 方法〕吹螅可以使用這個(gè)方法返回這個(gè) Variable 的 Observable 類型恩沽,拿到這個(gè) Observable 類型就能訂閱它了)
介紹了以上四種 subject ,接下來貼代碼并附上運(yùn)行打印截圖翔始,有興趣的可以copy下來運(yùn)行一遍罗心,了解其 event 執(zhí)行順序
PublishSubject代碼示例
let subject = PublishSubject<String>()
subject.onNext("first signal")
subject.subscribe(onNext: { (event) in
print("first event is"+event)
}, onCompleted: {
print("completed first")
}) {
print("first :銷毀了")
}.disposed(by: disposeB)
subject.onNext("second signal")
subject.subscribe(onNext: { (event) in
print("second event is "+event)
}, onCompleted: {
print("completed second")
}) {
print("second :銷毀了")
}.disposed(by: disposeB)
//讓subject結(jié)束,后面再進(jìn)行訂閱
subject.onCompleted()
subject.onNext("third signal")
subject.onNext("fourth signal")
subject.subscribe(onNext: { (event) in
print("this is another"+event)
}, onCompleted: {
print("completed another")
}) {
print("another :銷毀了")
}.disposed(by: disposeB)
BehaviorSubject代碼示例
let subject = BehaviorSubject(value: "first signal")
subject.onNext("another first signal") //會替換了 first signal 的信號
subject.subscribe(onNext: { (event) in
print(event)
} , onCompleted: {
print("completed")
}) {
print("第一個(gè)銷毀了")
}.disposed(by: disposeB)
subject.onNext("second signal")
subject.onNext("third signal") //這里試圖替換上面的 second signal 的event
subject.subscribe(onNext: { (event) in
print(event)
} , onCompleted: {
print("completed")
}) {
print("第二個(gè)銷毀了")
}.disposed(by: disposeB)
subject.onError(NSError(domain: "myError", code: 10010, userInfo: ["myUserInfo":"10010錯(cuò)誤"]))
ReplaySubject代碼示例
//設(shè)置緩存最近2個(gè)event
let subject = ReplaySubject<String>.create(bufferSize: 2)
subject.onNext("first")
subject.onNext("second")
subject.onNext("third")
subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print(error)
}, onCompleted: {
print("這是一個(gè) 完成")
}) {
print("銷毀了")
}.disposed(by: disposeB)
subject.onCompleted()//現(xiàn)在終結(jié)subject
subject.subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print(error)
}, onCompleted: {
print("完成之后的訂閱完成")
}) {
print("完成之后銷毀了")
}.disposed(by: disposeB)
Variable代碼示例
let subject = Variable("first")
subject.value = "second"
subject.asObservable().subscribe(onNext: { (event) in
print(event)
}, onError: { (error) in
print(error)
}, onCompleted: {
print("Variber訂閱完成")
}) {
print("Variber銷毀")
}
.disposed(by: disposeB)
subject.value = "third"
打印結(jié)果中給出了一個(gè)警告,在其GitHub的issue鏈接中城瞎,提到了 Variable 要在接下來的版本里刪除协屡,請用 BehaviorRelay 代替,其實(shí) Variable 封裝全谤,還是比較順手肤晓。貌似現(xiàn)在UI層的很多都是 Variable 來管理,但 RxSwift 也封裝了很多關(guān)于UI的认然,issue的回復(fù)中說以后會銷毀补憾,注意是銷毀 Variable 這個(gè)類。
該文章首次發(fā)表在 簡書:我只不過是出來寫寫代碼 博客卷员,并自動同步至 騰訊云:我只不過是出來寫寫iOS 博客