Subject介紹
從之前的文章RxSwift(三)-- RxSwift使用介紹Observable的創(chuàng)建中奕删,我們可以知道拄氯,當(dāng)我們需要?jiǎng)?chuàng)建一個(gè)
Observable
的時(shí)候,要預(yù)先將要發(fā)出的數(shù)據(jù)都準(zhǔn)備好满俗,等到有人訂閱它時(shí)再將數(shù)據(jù)通過Event
發(fā)出去菩鲜。
不過,有時(shí)我們也希望Observable
在運(yùn)行時(shí)能動(dòng)態(tài)地“獲得”或者說“產(chǎn)生”出一個(gè)新的數(shù)據(jù)胳螟,再通過Event
發(fā)送出去昔馋。比如:訂閱一個(gè)輸入框的輸入內(nèi)容,當(dāng)用戶每輸入一個(gè)字后糖耸,這個(gè)輸入框關(guān)聯(lián)的Observable
就會(huì)發(fā)出一個(gè)帶有輸入內(nèi)容的Event
秘遏,通知給所有訂閱者。
這個(gè)時(shí)候嘉竟,我們要介紹的Subject
就登場了邦危。
Subject基本介紹
-
Subject
它既是訂閱者洋侨,也是Observable
序列:
- 因?yàn)樗軌騽?dòng)態(tài)地接收新的值,所以它是訂閱者倦蚪。
- 因?yàn)?code>Subject有了新的值以后希坚,會(huì)通過
Event
事件將新的值發(fā)出來給到訂閱者,所以它又是一個(gè)Observable
序列陵且。
-
RxSwift
中Subject
的分類是:PublishSubject
裁僧、BehaviorSubject
、ReplaySubject
慕购、AsyncSubject
锅知、BehaviorRelay
,它們之間既有各自的特點(diǎn)脓钾,也有相同之處:
- 它們都是
Observable
序列售睹,訂閱者都能收到它們發(fā)出的新的Event
。- 等到
Subject
發(fā)出.complete
或者.error
的Event
可训,Subject
也就結(jié)束了昌妹,也就不會(huì)再發(fā)出.next
事件了。- 如果在
Subject
結(jié)束后再訂閱的訂閱者握截,也可以收到Subject
發(fā)出的一條.complete
或者.error
事件飞崖,用來告訴訂閱者已經(jīng)結(jié)束了。- 它們之間的最大區(qū)別是:當(dāng)一個(gè)新的訂閱者剛訂閱它的時(shí)候谨胞,能不能收到
Subject
以前發(fā)出過的舊Event
固歪,如果能的話又能收到多少個(gè)。
-
Subject
的常用方法:
onNext(:)
:是on(.next(:))
的簡便寫法胯努。該方法相當(dāng)于Subject
接收到一個(gè).next
事件牢裳。onError(:)
:是on(.error(:))
的簡便寫法。該方法相當(dāng)于Subject
接收到一個(gè).error
事件叶沛。onCompleted()
:是on(.completed)
的簡便寫法蒲讯。該方法相當(dāng)于 subject 接收到一個(gè).completed
事件。
PublishSubject
- 介紹
PublishSubject
不需要初始值就能創(chuàng)建(也就是可以為空)灰署。PublishSubject
的訂閱者從他們開始訂閱的時(shí)間點(diǎn)起判帮,可以收到訂閱后Subject
發(fā)出的新Event
事件,而不會(huì)收到他們在訂閱前已發(fā)出的Event
事件溉箕。
- 代碼展示
// 創(chuàng)建一個(gè)PublishSubject
let subject = PublishSubject<String>()
// 由于當(dāng)前沒有任何訂閱者晦墙,所以這條信息不會(huì)輸出到控制臺(tái)
subject.onNext("111")
// 第1次訂閱subject
subject.subscribe(onNext: { string in
print("第1次訂閱:", string)
}, onCompleted:{
print("第1次訂閱:onCompleted")
}).disposed(by: disposeBag)
// 當(dāng)前有1個(gè)訂閱,則該信息會(huì)輸出到控制臺(tái)
subject.onNext("222")
// 第2次訂閱subject
subject.subscribe(onNext: { string in
print("第2次訂閱:", string)
}, onCompleted:{
print("第2次訂閱:onCompleted")
}).disposed(by: disposeBag)
// 當(dāng)前有2個(gè)訂閱肴茄,則該信息會(huì)輸出到控制臺(tái)
subject.onNext("333")
// 讓subject結(jié)束
subject.onCompleted()
// subject完成后會(huì)發(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
需要通過一個(gè)默認(rèn)初始值來創(chuàng)建踩麦。- 當(dāng)一個(gè)訂閱者來訂閱它的時(shí)候枚赡,這個(gè)訂閱者會(huì)立即收到
BehaviorSubjects
上一個(gè)發(fā)出的event
事件,如果還沒有收到任何數(shù)據(jù)谓谦,則會(huì)發(fā)出一個(gè)默認(rèn)值贫橙。之后就跟PublishSubject
正常的情況一樣,它也會(huì)接收到BehaviorSubject
之后發(fā)出的新的event
事件反粥。
- 代碼展示
// 創(chuàng)建一個(gè)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í)候需要設(shè)置一個(gè)bufferSize
卢肃,表示它對(duì)于它發(fā)送過的event
的緩存?zhèn)€數(shù)。- 比如一個(gè)
ReplaySubject
的bufferSiz
e 設(shè)置為 2才顿,它發(fā)出了 3 個(gè).next
的event
莫湘,那么它會(huì)將后兩個(gè)(最近的兩個(gè))event
給緩存起來。此時(shí)如果有一個(gè)subscriber
訂閱了這個(gè)ReplaySubject
郑气,那么這個(gè)subscriber
就會(huì)立即收到前面緩存的兩個(gè).next
的event
幅垮。- 如果一個(gè)
subscriber
訂閱已經(jīng)結(jié)束的ReplaySubject
,除了會(huì)收到緩存的.next
的event
外尾组,還會(huì)收到那個(gè)終結(jié)的.error
或者.complete
的event
忙芒。
- 代碼展示
//創(chuàng)建一個(gè)bufferSize為2的ReplaySubject
let subject = ReplaySubject<String>.create(bufferSize: 2)
//連續(xù)發(fā)送3個(gè)next事件
subject.onNext("111")
subject.onNext("222")
subject.onNext("333")
//第1次訂閱subject
subject.subscribe { event in
print("第1次訂閱:", event)
}.disposed(by: disposeBag)
//再發(fā)送1個(gè)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í)也是對(duì)BehaviorSubject
的封裝讳侨,所以它也必須要通過一個(gè)默認(rèn)的初始值進(jìn)行創(chuàng)建呵萨。BehaviorRelay
具有BehaviorSubject
的功能,能夠向它的訂閱者發(fā)出上一個(gè)event
以及之后新創(chuàng)建的 event跨跨。- 與
BehaviorSubject
不同的是潮峦,不需要也不能手動(dòng)給BehaviorReply
發(fā)送completed
或者error
事件來結(jié)束它(BehaviorRelay
在銷毀時(shí)也不會(huì)自動(dòng)發(fā)送.complete
的event
)。BehaviorRelay
有一個(gè)value
屬性勇婴,我們通過這個(gè)屬性可以獲取最新值忱嘹。而通過它的accept()
方法可以對(duì)值進(jìn)行修改。
- 代碼展示
//創(chuàng)建一個(gè)初始值為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)爹橱。(這個(gè)常用在表格上拉加載功能上萨螺,BehaviorRelay
用來保存所有加載到的數(shù)據(jù))
//創(chuàng)建一個(gè)初始值為包含一個(gè)元素的數(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
- 介紹
- 一個(gè)
AsyncSubject
只在原始Observable
完成后,發(fā)射來自原始Observable
的最后一個(gè)值愧驱。- 如果原始
Observable
沒有發(fā)射任何值慰技,AsyncObject
也不發(fā)射任何值,它會(huì)把這最后一個(gè)值發(fā)射給任何后續(xù)的觀察者组砚。- 如果原始的
Observable
因?yàn)榘l(fā)生了錯(cuò)誤而終止吻商,AsyncSubject
將不會(huì)發(fā)射任何數(shù)據(jù),只是簡單的向前傳遞這個(gè)錯(cuò)誤通知糟红。
- 代碼展示
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