上節(jié)末尾员舵,我們提到了Subject。既然它可以同時作為Observable和Observer徘钥,我們就直奔主題变骡,從一個叫做PublishSubject
的對象開始离赫,感受下Subject的用法。
PublishSubject
顧名思義塌碌,PublishSubject
就像個出版社渊胸,到處收集內(nèi)容,此時它是一個Observer台妆,然后發(fā)布給它的訂閱者翎猛,此時,它是一個Observable接剩。
首先切厘,創(chuàng)建一個PublishSubject
很簡單,就像創(chuàng)建一個普通的類對象一樣:
let subject = PublishSubject<String>()
其中PublishSubject
的泛型參數(shù)懊缺,表示它可以訂閱到的疫稿,以及可以發(fā)布的事件類型。
其次,當我們把subject
當作Observer的時候而克,可以使用onNext
方法給它發(fā)送事件:
subject.onNext("Episode1 updated")
第三靶壮,當我們把subject
當作Observable的時候怔毛,訂閱它的代碼和訂閱普通的Observable完全一樣:
let sub1 = subject.subscribe(onNext: {
print("Sub1 - what happened: \($0)")
})
但是執(zhí)行一下就會發(fā)現(xiàn)员萍,控制臺上不會顯示任何訂閱消息,也就是說sub1
沒有訂閱到任何內(nèi)容拣度。這是因為PublishSubject
執(zhí)行的是“會員制”碎绎,它只會把最新的消息通知給消息發(fā)生之前的訂閱者。用序列圖表示出來抗果,就是這樣的:
可以看到筋帖,在紅燈之前訂閱,就可以訂閱到紅冤馏、綠日麸、藍全部事件,如果在藍燈之前訂閱逮光,就只能訂閱到藍色事件了代箭。于是,為了訂閱到subject
的事件涕刚,我們得把訂閱的代碼嗡综,放到通知subject
前面:
let sub1 = subject.subscribe(onNext: {
print("Sub1 - what happened: \($0)")
})
subject.onNext("Episode1 updated")
重新執(zhí)行下,就能看到Sub1 - what happened: Episode1 updated的通知了杜漠。然后极景,再來觀察下面代碼的執(zhí)行結(jié)果:
sub1.dispose()
let sub2 = subject.subscribe(onNext: {
print("Sub2 - what happened: \($0)")
})
subject.onNext("Episode2 updated")
subject.onNext("Episode3 updated")
sub2.dispose()
- 首先,在執(zhí)行過
sub1.dispose()
之后驾茴,sub1
就不會再接收來自subject
的任何消息了盼樟; - 其次,
subject
有了一個新的訂閱者sub2
锈至; - 第三晨缴,
subject
又捕獲到了兩條新的消息。按照剛才的說法裹赴,sub2
不會接收到訂閱之前的消息喜庞,因此,我們應該只能在控制臺看到Sub2 - what happened: Episode2 updated和Sub2 - what happened: Episode3 updated這兩條消息棋返; - 最后延都,
sub2
取消對subject
的訂閱;
重新執(zhí)行一下睛竣,就能在控制臺看到結(jié)果了晰房。
BehaviorSubject
如果你希望Subject從“會員制”變成“試用制”,就需要使用BehaviorSubject
。它和PublisherSubject
唯一的區(qū)別殊者,就是只要有人訂閱与境,它就會向訂閱者發(fā)送最新的一次事件作為“試用”。
如圖所示猖吴,BehaviorSubject
帶有一個紫燈作為默認消息摔刁,當紅燈之前訂閱時,就會收到紫色及以后的所有消息海蔽。而在綠燈之后訂閱共屈,就只會收到綠燈及以后的所有消息了。因此党窜,當初始化一個BehaviorSubject
對象的時候拗引,要給它指定一個默認的推送消息:
let subject = BehaviorSubject<String>(
value: "RxSwift step by step")
然后,當我們再執(zhí)行先訂閱幌衣,后發(fā)送消息的邏輯時:
let sub1 = subject.subscribe(onNext: {
print("Sub1 - what happened: \($0)")
})
subject.onNext("Episode1 updated")
由于BehaviorSubject
有了一個默認的事件矾削,sub1
訂閱之后,就會陸續(xù)收到RxSwift step by step和Sub1 - what happened: Episode1 updated的消息了豁护。此時哼凯,如果我們再添加一個新的訂閱者:
let sub2 = subject.subscribe(onNext: {
print("Sub2 - what happened: \($0)")
})
此時,sub2
就只能訂閱到Sub2 - what happened: Episode1 updated消息了择镇。如果我們要讓sub2
在訂閱的時候獲取到過去所有的消息挡逼,就需要使用ReplaySubject
。
ReplaySubject
ReplaySubject
的行為和BehaviorSubject
類似腻豌,都會給訂閱者發(fā)送歷史消息家坎。不同地方有兩點:
-
ReplaySubject
沒有默認消息,訂閱空的ReplaySubject
不會收到任何消息吝梅; -
ReplaySubject
自帶一個緩沖區(qū)虱疏,當有訂閱者訂閱的時候,它會向訂閱者發(fā)送緩沖區(qū)內(nèi)的所有消息苏携;
ReplaySubject
緩沖區(qū)的大小做瞪,是在創(chuàng)建的時候確定的:
let subject = ReplaySubject<String>.create(bufferSize: 2)
這樣,我們就創(chuàng)建了一個可以緩存兩個消息的ReplaySubject
右冻。作為Observable装蓬,它此時是一個空的事件序列,訂閱它纱扭,不會收到任何消息:
let sub1 = subject.subscribe(onNext: {
print("Sub1 - what happened: \($0)")
})
然后牍帚,我們讓subject
接收3個事件,sub1
就會收到三次事件訂閱:
subject.onNext("Episode1 updated")
subject.onNext("Episode2 updated")
subject.onNext("Episode3 updated")
// Sub1 - what happened: Episode1 updated
// Sub1 - what happened: Episode2 updated
// Sub1 - what happened: Episode3 updated
這時乳蛾,我們再給subject
添加一個訂閱者:
let sub2 = subject.subscribe(onNext: {
print("Sub2 - what happened: \($0)")
})
// Sub2 - what happened: Episode2 updated
// Sub2 - what happened: Episode3 updated
由于subject
緩沖區(qū)的大小是2暗赶,它會自動給sub2
發(fā)送最新的兩次歷史事件鄙币。在控制臺中執(zhí)行一下,就可以看到注釋中的結(jié)果了蹂随。
Variable
除了事件序列之外十嘿,在平時的編程中我們還經(jīng)常需遇到一類場景,就是需要某個值是有“響應式”特性的岳锁,例如可以通過設置這個值來動態(tài)控制按鈕是否禁用绩衷,是否顯示某些內(nèi)容等。為了方便這個操作浸锨,RxSwift還提供了一個特殊的subject唇聘,叫做Variable
版姑。
我們可以像定義一個普通變量一樣定義一個Variable
:
let stringVariable = Variable("Episode1")
當我們要訂閱一個Variable
對象的時候柱搜,要先明確使用asObservable()
方法。而不像其他subject一樣直接訂閱:
let stringVariable = Variable("Episode1")
let sub1 = stringVariable
.asObservable()
.subscribe {
print("sub1: \($0)")
}
// sub1: next(Episode1)
而當我們要給一個Variable
設置新值的時候剥险,要明確訪問它的value
屬性聪蘸,而不是使用onNext
方法:
stringVariable.value = "Episode2"
// sub1: next(Episode2)
最后要說明的一點是,Variable
只用來表達一個“響應式”值的語義表制,因此健爬,它有以下兩點性質(zhì):
- 絕不會發(fā)生
.error
事件; - 無需手動給它發(fā)送
.complete
事件表示完成么介;
因此娜遵,下面的代碼都會導致編譯錯誤:
// !!! The following code CANNOT compile !!!
stringVariable.asObservable().onError(MyError.myError)
stringVariable.asObservable().onCompleted()
What's next?
以上,就是RxSwift中4種Subject的用法壤短。至此设拟,我們就一切準備就緒了,接下來久脯,我們就在一個真實的App里纳胧,逐步了解如何用RxSwift實現(xiàn)一些之前常見的開發(fā)任務。