Subject介紹
從之前的文章RxSwift(三)-- RxSwift使用介紹Observable的創(chuàng)建中,我們可以知道,當(dāng)我們需要創(chuàng)建一個
Observable的時候,要預(yù)先將要發(fā)出的數(shù)據(jù)都準(zhǔn)備好,等到有人訂閱它時再將數(shù)據(jù)通過Event發(fā)出去。
不過,有時我們也希望Observable在運(yùn)行時能動態(tài)地“獲得”或者說“產(chǎn)生”出一個新的數(shù)據(jù),再通過Event發(fā)送出去。比如:訂閱一個輸入框的輸入內(nèi)容,當(dāng)用戶每輸入一個字后,這個輸入框關(guān)聯(lián)的Observable就會發(fā)出一個帶有輸入內(nèi)容的Event,通知給所有訂閱者。
這個時候,我們要介紹的Subject就登場了。
Subject基本介紹
-
Subject它既是訂閱者,也是Observable序列:
- 因?yàn)樗軌騽討B(tài)地接收新的值,所以它是訂閱者。
- 因?yàn)?code>Subject有了新的值以后,會通過
Event事件將新的值發(fā)出來給到訂閱者,所以它又是一個Observable序列。
-
RxSwift中Subject的分類是:PublishSubject、BehaviorSubject、ReplaySubject、AsyncSubject、BehaviorRelay,它們之間既有各自的特點(diǎn),也有相同之處:
- 它們都是
Observable序列,訂閱者都能收到它們發(fā)出的新的Event。- 等到
Subject發(fā)出.complete或者.error的Event,Subject也就結(jié)束了,也就不會再發(fā)出.next事件了。- 如果在
Subject結(jié)束后再訂閱的訂閱者,也可以收到Subject發(fā)出的一條.complete或者.error事件,用來告訴訂閱者已經(jīng)結(jié)束了。- 它們之間的最大區(qū)別是:當(dāng)一個新的訂閱者剛訂閱它的時候,能不能收到
Subject以前發(fā)出過的舊Event,如果能的話又能收到多少個。
-
Subject的常用方法:
onNext(:):是on(.next(:))的簡便寫法。該方法相當(dāng)于Subject接收到一個.next事件。onError(:):是on(.error(:))的簡便寫法。該方法相當(dāng)于Subject接收到一個.error事件。onCompleted():是on(.completed)的簡便寫法。該方法相當(dāng)于 subject 接收到一個.completed事件。
PublishSubject
- 介紹
PublishSubject不需要初始值就能創(chuàng)建(也就是可以為空)。PublishSubject的訂閱者從他們開始訂閱的時間點(diǎn)起,可以收到訂閱后Subject發(fā)出的新Event事件,而不會收到他們在訂閱前已發(fā)出的Event事件。
- 代碼展示
// 創(chuàng)建一個PublishSubject
let subject = PublishSubject<String>()
// 由于當(dāng)前沒有任何訂閱者,所以這條信息不會輸出到控制臺
subject.onNext("111")
// 第1次訂閱subject
subject.subscribe(onNext: { string in
print("第1次訂閱:", string)
}, onCompleted:{
print("第1次訂閱:onCompleted")
}).disposed(by: disposeBag)
// 當(dāng)前有1個訂閱,則該信息會輸出到控制臺
subject.onNext("222")
// 第2次訂閱subject
subject.subscribe(onNext: { string in
print("第2次訂閱:", string)
}, onCompleted:{
print("第2次訂閱:onCompleted")
}).disposed(by: disposeBag)
// 當(dāng)前有2個訂閱,則該信息會輸出到控制臺
subject.onNext("333")
// 讓subject結(jié)束
subject.onCompleted()
// subject完成后會發(fā)出.next事件了。
subject.onNext("444")
// subject完成后它的所有訂閱(包括結(jié)束后的訂閱),都能收到subject的.completed事件,
subject.subscribe(onNext: { string in
print("第3次訂閱:", string)
}, onCompleted:{
print("第3次訂閱:onCompleted")
}).disposed(by: disposeBag)
運(yùn)行結(jié)果:
第1次訂閱: 222
第1次訂閱: 333
第2次訂閱: 333
第1次訂閱:onCompleted
第2次訂閱:onCompleted
第3次訂閱:onCompleted
BehaviorSubject
- 介紹
BehaviorSubject需要通過一個默認(rèn)初始值來創(chuàng)建。- 當(dāng)一個訂閱者來訂閱它的時候,這個訂閱者會立即收到
BehaviorSubjects上一個發(fā)出的event事件,如果還沒有收到任何數(shù)據(jù),則會發(fā)出一個默認(rèn)值。之后就跟PublishSubject正常的情況一樣,它也會接收到BehaviorSubject之后發(fā)出的新的event事件。
- 代碼展示
// 創(chuàng)建一個BehaviorSubject
let subject = BehaviorSubject(value: "111")
// 第1次訂閱subject
subject.subscribe { event in
print("第1次訂閱:", event)
}.disposed(by: disposeBag)
// 發(fā)送next事件
subject.onNext("222")
// 發(fā)送error事件
subject.onError(NSError(domain: "local", code: 0, userInfo: nil))
// 第2次訂閱subject
subject.subscribe { event in
print("第2次訂閱:", event)
}.disposed(by: disposeBag)
運(yùn)行結(jié)果:
第1次訂閱: next(111)
第1次訂閱: next(222)
第1次訂閱: error(Error Domain=local Code=0 "(null)")
第2次訂閱: error(Error Domain=local Code=0 "(null)")
ReplaySubject
- 介紹
ReplaySubject在創(chuàng)建時候需要設(shè)置一個bufferSize,表示它對于它發(fā)送過的event的緩存?zhèn)€數(shù)。- 比如一個
ReplaySubject的bufferSize 設(shè)置為 2,它發(fā)出了 3 個.next的event,那么它會將后兩個(最近的兩個)event給緩存起來。此時如果有一個subscriber訂閱了這個ReplaySubject,那么這個subscriber就會立即收到前面緩存的兩個.next的event。- 如果一個
subscriber訂閱已經(jīng)結(jié)束的ReplaySubject,除了會收到緩存的.next的event外,還會收到那個終結(jié)的.error或者.complete的event。
- 代碼展示
//創(chuàng)建一個bufferSize為2的ReplaySubject
let subject = ReplaySubject<String>.create(bufferSize: 2)
//連續(xù)發(fā)送3個next事件
subject.onNext("111")
subject.onNext("222")
subject.onNext("333")
//第1次訂閱subject
subject.subscribe { event in
print("第1次訂閱:", event)
}.disposed(by: disposeBag)
//再發(fā)送1個next事件
subject.onNext("444")
//第2次訂閱subject
subject.subscribe { event in
print("第2次訂閱:", event)
}.disposed(by: disposeBag)
//讓subject結(jié)束
subject.onCompleted()
//第3次訂閱subject
subject.subscribe { event in
print("第3次訂閱:", event)
}.disposed(by: disposeBag)
運(yùn)行結(jié)果:
第1次訂閱: next(222)
第1次訂閱: next(333)
第1次訂閱: next(444)
第2次訂閱: next(333)
第2次訂閱: next(444)
第1次訂閱: completed
第2次訂閱: completed
第3次訂閱: next(333)
第3次訂閱: next(444)
第3次訂閱: completed
BehaviorRelay
- 介紹
BehaviorRelay是作為Variable的替代者出現(xiàn)的。它的本質(zhì)其實(shí)也是對BehaviorSubject的封裝,所以它也必須要通過一個默認(rèn)的初始值進(jìn)行創(chuàng)建。BehaviorRelay具有BehaviorSubject的功能,能夠向它的訂閱者發(fā)出上一個event以及之后新創(chuàng)建的 event。- 與
BehaviorSubject不同的是,不需要也不能手動給BehaviorReply發(fā)送completed或者error事件來結(jié)束它(BehaviorRelay在銷毀時也不會自動發(fā)送.complete的event)。BehaviorRelay有一個value屬性,我們通過這個屬性可以獲取最新值。而通過它的accept()方法可以對值進(jìn)行修改。
- 代碼展示
//創(chuàng)建一個初始值為111的BehaviorRelay
let subject = BehaviorRelay<String>(value: "111")
//修改value值
subject.accept("222")
//第1次訂閱
subject.asObservable().subscribe {
print("第1次訂閱:", $0)
}.disposed(by: disposeBag)
//修改value值
subject.accept("333")
//第2次訂閱
subject.asObservable().subscribe {
print("第2次訂閱:", $0)
}.disposed(by: disposeBag)
//修改value值
subject.accept("444")
運(yùn)行結(jié)果:
第1次訂閱: next(222)
第1次訂閱: next(333)
第2次訂閱: next(333)
第1次訂閱: next(444)
第2次訂閱: next(444)
- 另外,如果想將新值合并到原值上,可以通過
accept()方法與value屬性配合來實(shí)現(xiàn)。(這個常用在表格上拉加載功能上,BehaviorRelay用來保存所有加載到的數(shù)據(jù))
//創(chuàng)建一個初始值為包含一個元素的數(shù)組的BehaviorRelay
let subject = BehaviorRelay<[String]>(value: ["1"])
//修改value值
subject.accept(subject.value + ["2", "3"])
//第1次訂閱
subject.asObservable().subscribe {
print("第1次訂閱:", $0)
}.disposed(by: disposeBag)
//修改value值
subject.accept(subject.value + ["4", "5"])
//第2次訂閱
subject.asObservable().subscribe {
print("第2次訂閱:", $0)
}.disposed(by: disposeBag)
//修改value值
subject.accept(subject.value + ["6", "7"])
運(yùn)行結(jié)果:
第1次訂閱: next(["1", "2", "3"])
第1次訂閱: next(["1", "2", "3", "4", "5"])
第2次訂閱: next(["1", "2", "3", "4", "5"])
第1次訂閱: next(["1", "2", "3", "4", "5", "6", "7"])
第2次訂閱: next(["1", "2", "3", "4", "5", "6", "7"])
AsyncSubject
- 介紹
- 一個
AsyncSubject只在原始Observable完成后,發(fā)射來自原始Observable的最后一個值。- 如果原始
Observable沒有發(fā)射任何值,AsyncObject也不發(fā)射任何值,它會把這最后一個值發(fā)射給任何后續(xù)的觀察者。- 如果原始的
Observable因?yàn)榘l(fā)生了錯誤而終止,AsyncSubject將不會發(fā)射任何數(shù)據(jù),只是簡單的向前傳遞這個錯誤通知。
- 代碼展示
let subject = AsyncSubject<Int>()
subject.onNext(1)
subject.subscribe(onNext: { int in
print("observerA: \(int)")
}, onCompleted: {
print("observerA: onCompleted")
}).disposed(by: disposeBag)
subject.onNext(2)
subject.subscribe(onNext: { int in
print("observerB: \(int)")
}, onCompleted: {
print("observerB: onCompleted")
}).disposed(by: disposeBag)
subject.onNext(3)
subject.subscribe(onNext: { int in
print("observerC: \(int)")
}, onCompleted: {
print("observerC: onCompleted")
}).disposed(by: disposeBag)
subject.onCompleted()
subject.onNext(4)
subject.subscribe(onNext: { int in
print("observerD: \(int)")
}, onCompleted: {
print("observerD: onCompleted")
}).disposed(by: disposeBag)
運(yùn)行結(jié)果:
observerA: 3
observerB: 3
observerC: 3
observerA: onCompleted
observerB: onCompleted
observerC: onCompleted
observerD: 3
observerD: onCompleted