本文章內(nèi)部分圖片資源來自RayWenderlich.com
本文結(jié)合自己的理解來總結(jié)介紹一下RxSwift最基本的一些概念,當(dāng)然只這一篇是肯定介紹不完RxSwift的,這篇文算是起個頭,以后有時間時候則會繼續(xù)
簡要概述
"Rx"是ReactiveX的縮寫,它是目前比較流行比較火的一種開發(fā)方式的庫,"Rx"本身可以說是一種跨平臺的標(biāo)準(zhǔn),不管是web還是移動開發(fā),都能用"Rx"的思維和方法來完成你的工作。
"Rx"有自己的社區(qū)論壇。除了RxSwift之外,還有類似RxJava, RxJS, RxKotlin, Rx.NET........都是基于不同的開發(fā)語言的Rx的庫,他們之間其實都是相通的,都有相同的API,除了用的語言不同,所以說如果以后你使用別的語言做別的方面的開發(fā),同樣是可以用到相同的思維甚至相同的方法接口(除了語言不同)來編程。
這是Rx大家庭的主頁地址:reactivex
在里面可以看到Rx大家庭的所有成員如下

Rx自己的定義是這樣寫的:
ReactiveX is a library for composing asynchronous and event-based programs by using observable sequences.
Rx就是基于異步Event(事件)序列的響應(yīng)式編程,它可以簡化異步編程方法,提供更優(yōu)雅的數(shù)據(jù)綁定,讓你可以時刻響應(yīng)新的數(shù)據(jù)同時順序地處理它們。
另外如果有使用MVVM開發(fā)模式的小伙伴通過RxSwift就可以獲得更加方便的數(shù)據(jù)綁定的方法,可以使得你的MVVM如虎添翼。
這是RxSwift在github上的地址:RXSwift
可以在這個地址頁面下方看到,如果你使用CocoaPods來引入RXSwift到你項目工程里時候,它讓你要引入兩個庫,如下
pod 'RxSwift', '~> 3.0'
pod 'RxCocoa', '~> 3.0'
那么這個RxCocoa又是什么呢?上面說到RxSwift它并純不是針對iOS開發(fā),而只是基于Swift語言的Rx標(biāo)準(zhǔn)實現(xiàn)接口庫,所以RxSwift里不包含任何Cocoa或者UI方面的類。
而RxCocoa就是基于RxSwift針對于iOS開發(fā)的一個庫,它通過Extension的方法給原生的比如UI控件添加了Rx的特性,使得你更容易訂閱和響應(yīng)這些控件的事件。
或者再極端一點說就是:使用Rx可以對你的程序里的事件傳遞響應(yīng)方法做到一統(tǒng)江湖,要將以前你常用的那些事件傳遞方法,比如delegate、notification、target-action等等全部替換成Rx的"信號鏈"方式。
不過這篇文章里不會去寫RxCocoa的使用方法,而是主要介紹RxSwift中最基本的核心概念,只有從最根本的理解了才能使用的得心應(yīng)手。
Rx的根基Observables
Observable<T>這個類就是Rx框架的基礎(chǔ),它的作用就是可以異步地產(chǎn)生一系列的Event(事件),同時這些Event還可以攜帶數(shù)據(jù),它的泛型<T>就是用來指定這個Event攜帶的數(shù)據(jù)的類型。
即一個Observable<T>對象會隨著時間推移不定期地發(fā)出event(element : T)這樣一個東西。
不過首先需要有一個Observer訂閱者來訂閱Observable<T>,這樣這個訂閱者才能收到Observable<T>不時發(fā)出的Event。
如果你進(jìn)入RxSwift代碼里看看就能看到事件Event的定義如下:
public enum Event<Element> {
/// Next element is produced.
case next(Element)
/// Sequence terminated with an error.
case error(Swift.Error)
/// Sequence completed successfully.
case completed
}
可以看到Event的定義就是一個枚舉,也就是一個Observable是可以發(fā)出3種不同類型的Event事件:
next:next事件就是那個可以攜帶數(shù)據(jù)<T>的事件,可以說它就是一個“最正?!钡氖录?。
error:error事件表示一個錯誤,它可以攜帶具體的錯誤內(nèi)容,一旦Observable發(fā)出了error event,則這個Observable就等于終止了,以后它再也不會發(fā)出event事件了。
completed:completed事件表示Observable發(fā)出的事件正常地結(jié)束了,跟error一樣,一旦Observable發(fā)出了completed event,則這個Observable就等于終止了,以后它再也不會發(fā)出event事件了。

從上圖可以看出Observable就相當(dāng)于一個sequence(序列),它是基于時間的,圖片中的三個圈就相當(dāng)于在三個不同的時間點上發(fā)出的Event事件。因為這個Observable 的泛型是Int:Observable<Int>,則表示它發(fā)出的Event攜帶的數(shù)據(jù)的數(shù)據(jù)類型是Int,就好像圖上的一樣,三個Event攜帶的數(shù)據(jù)分別是數(shù)字1、2和3。


上面兩個圖分別表示了兩個Observable分別以Completed Event和Error Event為終結(jié),一旦Observable終結(jié)了,則它以后再也不會發(fā)出新的Event 了。
創(chuàng)建Observable
我們來寫實際寫一些代碼,來創(chuàng)建Observable和訂閱它。你可以不用創(chuàng)建一個App項目工程,創(chuàng)建一個Xcode提供的playground項目即可。另外不管你是創(chuàng)建app還是playground,都請先導(dǎo)入RxSwift這個庫?。。?/p>
我們來創(chuàng)建幾個Observable,Observable提供了just,of,from方法來通過默認(rèn)值創(chuàng)建一個Observable,如下
// 1
let observable: Observable<Int> = Observable<Int>.just(1)
// 2
let observable2 = Observable.of("One", "Two", "Three")
// 3
let observable3 = Observable.from([1, 2, 3])
我們分別通過三個方法來創(chuàng)建了三個observable對象
1.第一個通過just()方法,這個方法通過傳入一個默認(rèn)值來初始化??梢钥吹轿覀冿@式地標(biāo)注出了observable的類型為Observable<Int>,指定了這個Observable所發(fā)出的事件攜帶的數(shù)據(jù)類型必須是Int類型的。
2.第二個通過of()方法創(chuàng)建,這個方法可以接受可變數(shù)量的參數(shù),不過注意他們一定要是同類型的,可以看到我并沒有顯式地聲明出Observable2的泛型類型,因為Swift會自動推斷類型,它看到我傳入的element全是String類型,便默認(rèn)地認(rèn)為Observable2的類型為Observable<String>。你可以按住Alt鍵同時鼠標(biāo)點擊observable2,看看它是不是真的是Observable<String>

3.第三種方法通過from()創(chuàng)建,它需要一個數(shù)組參數(shù),而數(shù)據(jù)里的元素就會被當(dāng)做這個observable3所發(fā)出event攜帶的數(shù)據(jù)內(nèi)容,也就是用of()方法創(chuàng)建和把of()方法所有元素放在一個數(shù)組里再傳入from()方法創(chuàng)建的效果是一樣的。你也可以按住Alt看看observable3的類型會被推斷為Observable<Int>而不是Observable<Array>

訂閱Observable
光有了Observable還不行,還需要有人來訂閱它,它才能發(fā)出Event,不然沒有理它它的Event發(fā)給誰聽呢?
在上面創(chuàng)建Obeservale的代碼下面加入如下代碼:
func subscribeOne() {
print("------------ subscribe one ------------")
observable.subscribe { event in
print(event)
}
print("------------ subscribe two ------------")
observable2.subscribe { event in
print(event)
}
print("------------ subscribe three ------------")
observable3.subscribe { event in
print(event)
}
}
記得要調(diào)用一下這個測試方法subscribeOne() 。
很簡單,我們通過subscribe()訂閱了之前創(chuàng)建的3個Observable對象,這個block的回調(diào)參數(shù)就是被發(fā)出的event事件,我們直接print打印出來看看結(jié)果是什么:

可以看到我們在初始化Observable對象時候設(shè)置的默認(rèn)值都被順序地通過.next事件發(fā)送了出來,當(dāng)Observable對象的初始數(shù)據(jù)都發(fā)送完了,它還會自動地發(fā)送一個.completed事件出來。
但是注意此時打印出來的是event是Event類型,比如上面看到的next(1),next(One)等等,我們?nèi)绻@取到這個事件里的數(shù)據(jù)呢?很簡單,通過event.element即可獲取到。但是這樣不是有點麻煩么,每次都要去event里讀取這個屬性,所以RxSwift還提供了另一個subscribe方法如下:
func subscribeTwo() {
observable3.subscribe(onNext: { element in
print(element)
}, onError: { error in
print(error)
}, onCompleted: {
print("completed")
}, onDisposed: {
})
}
先將上面調(diào)用subscribeOne() 代碼給注釋掉,再調(diào)用一次subscribeTwo()看看結(jié)果

可以看到這個方法其實就是將event給分類了,通過不同的block進(jìn)行回調(diào),.next就通過onNext回調(diào),.error的就通過onError回調(diào),同時它會把event攜帶的數(shù)據(jù)直接解包出來作為參數(shù)直接回調(diào)回來,所以我們print(element)打印出來的結(jié)果就是.next事件所攜帶的數(shù)據(jù)了。
有人可能注意到最后有一個onDisposed的block,這個稍后會講到,暫時可以不用管。
PS: subscribe()方法的onNext、onError、onCompleted和onDisposed這四個回調(diào)block參數(shù)都是有默認(rèn)值的,即它們都是可選的,你可以只設(shè)置onNext而不管其他的情況,比如:observable.subscribe( onNext: { print($0) } )。
垃圾回收Dispose
一個Observable被創(chuàng)建出來后它不會馬上就開始被激活從而發(fā)出Event,而是要等到它被某個人訂閱了才會激活它,激活之后一直等到Observable發(fā)出了.error或者.completed的event后,它才被終結(jié)。同時你也可以手動的取消一個訂閱的行為,當(dāng)你覺得這個訂閱結(jié)束了不再需要了就需要調(diào)用對應(yīng)的方法把這個訂閱給銷毀掉,有點類似以前的內(nèi)存管理,否則可能會引起內(nèi)存泄漏。
當(dāng)你對一個Observable調(diào)用訂閱方法的時候,這個方法其實是有返回值的,返回值的類型是Disposable,從它的類型名字意思就可以看出,這個類型是可丟棄可銷毀的。如果你進(jìn)入RxSwift的代碼里看一看:
/// Respresents a disposable resource.
public protocol Disposable {
/// Dispose resource.
func dispose()
}
Disposable其實就是一個protocol協(xié)議,而這個協(xié)議里只有一個方法就是dispose(),所以要取消一個訂閱行為這就要用到Disposable協(xié)議里的dispose()方法即可。
方法如下:
func disposeOne() {
// 1
let subscription = observable.subscribe { event in
print(event)
}
// 2
subscription.dispose()
}
1.訂閱我們最開始創(chuàng)建過的observable對象,并且使用一個叫subscription的常量來接收訂閱方法的返回值
2.對這個訂閱行為調(diào)用dispose()方法
注意,如果一個訂閱行為被dispose了,那么之后observable如果再發(fā)出event,這個已經(jīng)dispose的訂閱就收不到消息了(雖然當(dāng)前例子中的observable不會再發(fā)出event了)
除了世界使用dispose()方法之外,還有一個平時更常用dispose訂閱的模式,是使用一個叫DisposeBag的對象來管理一堆訂閱行為的銷毀,代碼如下
func disposeTwo() {
// 1
let disposeBag = DisposeBag()
// 2
observable2.subscribe { event in
print(event)
}.disposed(by: disposeBag)
// 3
observable3.subscribe { event in
print(event)
}.disposed(by: disposeBag)
}
1.創(chuàng)建一個DisposeBag對象,可以把它看成一個垃圾袋,把用過的訂閱行為都丟進(jìn)去,然后這個disposeBag就會在自己快要dealloc的時候?qū)λ锩娴乃杏嗛喰袨槎颊{(diào)用dispose()方法。
2.訂閱我們最開始創(chuàng)建的observable2,緊接著就把它丟進(jìn)我們的“垃圾袋”里。
3.同理2,對最開始創(chuàng)建的observable3做同樣的操作。
好的說完了Dispose,我們現(xiàn)在再想想前面那個subcribe()方法里,有一個我們還沒有解釋的onDisposed的block的作用是什么。不過我感覺現(xiàn)在也不用怎么解釋你也應(yīng)該知道了,它就是在這個訂閱行為被dispose之后會回調(diào)的block啦!
其他創(chuàng)建方法
Observable初始化除了上面提到的just,of,from之外,還有可以通過empty()創(chuàng)建一個空內(nèi)容的Observable,也能通過never()方法創(chuàng)建一個永遠(yuǎn)不會發(fā)出Event的Observable,還能通過range()方法指定起始和結(jié)束數(shù)值,來通過值的范圍創(chuàng)建一個用這個范圍內(nèi)所有值作為初始值的Observable。
另外有兩個比較值得一說的就是Observable創(chuàng)建方法,一個就叫create(),一個叫deferred():
create()方法
Observable 可通過create()方法創(chuàng)建,create方法接受一個block形式的參數(shù),這個block任務(wù)就是處理一個訂閱來了的處理情況。直接看代碼更簡單:
func create() {
// 1
let ob = Observable<String>.create{observer in
// 2
observer.onNext("a")
// 3
observer.onCompleted()
// 4
return Disposables.create()
}
// 5
ob.subscribe {
print($0)
}
}
1.通過create創(chuàng)建一個泛型為String的Observable對象,注意看他的block參數(shù),這個block有一個回調(diào)參數(shù)observer就是訂閱這個Observable對象的訂閱者,可以理解為當(dāng)一個訂閱者訂閱這個Observable對象的時候,就會將訂閱者作為參數(shù)傳入這個block來執(zhí)行一些內(nèi)容。
2.我們對訂閱者發(fā)出了.next事件,且攜帶了一個數(shù)據(jù)a
3.對訂閱者發(fā)出了.completed事件
4.最后因為一個訂閱行為會有一個Disposable類型的返回值,所以在結(jié)尾一定要returen一個Disposable
5.訂閱測試
看一看這個測試方法運行結(jié)果:

deferred()方法
deferred()創(chuàng)建方法,使用這個方法創(chuàng)建Observable對象相當(dāng)于是一個Observable工廠,deferred()方法需要傳入一個block來執(zhí)行延遲創(chuàng)建的行為,這個block里就是真正的實例化對象的地方。為了更容易理解就直接上代碼:
func deferredTest() {
// 1
var chinese = false
// 2
let factory : Observable<String> = Observable.deferred {
// 3
chinese = !chinese
// 4
if chinese {
return Observable.of("一", "二", "三")
}else {
return Observable.of("One", "Two", "Three")
}
}
// 5
let disposeBag = DisposeBag()
// 6
factory.subscribe { event in
print("1:", event)
}.disposed(by: disposeBag)
// 7
factory.subscribe { event in
print("2:", event)
}.disposed(by: disposeBag)
}
1.我們創(chuàng)建了一個Bool類型的變量來表示是否為中文
2.我們創(chuàng)建了一個Observable工廠,雖然它對外看起來更其他Observable沒什么不同,就是一個Observable<String>類型。但是我們通過deferred()方法將它的初始化給延遲了,通過傳入的block來做Observable實例的初始化并且返回。
3.我們先翻轉(zhuǎn)chinese,讓每次執(zhí)行這個block時候都不同
4.我們根據(jù)chinese標(biāo)示來選擇性的創(chuàng)建是包含中文還是英文的1、2、3值的Observable實例對象并且返回。
至此我們創(chuàng)建了一個Observable工廠,也就是說你每次調(diào)用factory獲取到的是不同的Observable對象,接下來的代碼就是用來驗證的。
5.創(chuàng)建了一個DisposeBag
6.訂閱factory,并且打印出來event,同時通過打印一個"1"表示這是第一個訂閱的結(jié)果
7.同理再次訂閱factory,打印結(jié)果通過2來區(qū)分。
現(xiàn)在來調(diào)用一次我們新寫的這個deferredTest()方法,看看輸出結(jié)果是什么:

可以看到我們雖然兩次都是訂閱了factory,但其實訂閱的真是Observable對象是不同的,一個發(fā)出Event的值是中文的,一個發(fā)出的Event的值是英文的。
Subjects
接下來進(jìn)入這篇的第二個主題就是Subjects。
你可能會發(fā)現(xiàn)上面的說的Observable有個問題就是:我們在創(chuàng)建一個Observable的時候就要預(yù)先將它以后要發(fā)出的Event所攜帶的數(shù)據(jù)都準(zhǔn)備好,等到有人訂閱它再將數(shù)據(jù)通過Event發(fā)出去。
而實際情況通常是需要Observable在運行時動態(tài)地“收到”或者說“產(chǎn)生”出一個新的數(shù)據(jù),再通過Event發(fā)送出去。也就是這些數(shù)據(jù)不是事先定好的,而已在程序運行的時候才能知道的。比如說如果我們訂閱著一個輸入框的輸入內(nèi)容,我們不可能事先就知道用戶會輸入什么,而是用戶每輸入一個字,這個輸入框關(guān)聯(lián)的Observable就會發(fā)出一個Event攜帶著這個用戶輸入的內(nèi)容,通知給所有訂閱者。
所以我們真正需要的應(yīng)該是一個類似即是可以發(fā)出Event的Observable,同樣也是可以接受新數(shù)據(jù)的訂閱者。這個就是我們要說的Subjects,Subjects能夠動態(tài)地接收新的值,這就相當(dāng)于它本身一定程度上是一個訂閱者。當(dāng)它有了新的值之后就會通過Event將新值發(fā)出給他的所有訂閱者,這樣看來它又是一個Observable了。
Subjects的分類
一共有四種Subjects,分別叫做PublishSubject,BehaviorSubject,ReplaySubject和Variable。他們之間其實大致相同,但是有具體自己鮮明的特點,可以針對不同的使用場景進(jìn)行選擇。
可以說他們都是Observable,他們的訂閱者都能收到他們發(fā)出的新的Event,他們之間最大的區(qū)別只是在于一個新的訂閱者剛訂閱它的時刻能不能收到Subject以前發(fā)出過的舊Event,如果能的話那么收到多少個。
下面來一一地介紹
PublishSubjects
PublishSubject可以說是最普通的Subject,它不需要初始值就能創(chuàng)建。PublishSubject的訂閱者從他們開始訂閱的時間點起,可以收到以后Subject發(fā)出的新Event,而不會收到他們訂閱前已發(fā)出的Event。
直到Subject發(fā)出.complete或者.error的Event后,Subject則終結(jié)了,它也就不會再發(fā)出.next事件。但是對于在subject終結(jié)后再訂閱他的訂閱者,也能收到subject發(fā)出的一條.complete或者.error的event,告訴這個新的訂閱者它已經(jīng)終結(jié)了。
看一看下面這個時序圖就跟直觀的理解了,最上面這條是一個PublishSubject,他在三個事件點上發(fā)出了三個Event,第二條和第三條線是兩個新的訂閱,虛線向上的箭頭表示他們訂閱PublishSubject的動作,可以很清楚的看看PublishSubject的訂閱者只能收到他們訂閱后的Event。

接下來上代碼:
func publishSubject() {
// 1
let disposeBag = DisposeBag()
// 2
let subject = PublishSubject<String>()
// 3
subject.onNext("Hello_1")
// 4
subject.subscribe(onNext: { string in
print("subscribe_1:", string)
}, onCompleted:{
print("subscribe_1: onCompleted")
}).disposed(by: disposeBag)
// 5
subject.onNext("Hello_2")
// 6
subject.subscribe(onNext: { string in
print("subscribe_2:", string)
}, onCompleted:{
print("subscribe_2: onCompleted")
}).disposed(by: disposeBag)
// 7
subject.onNext("Hello_3")
// 8
subject.onCompleted()
// 9
subject.onNext("Hello_4")
// 10
subject.subscribe(onNext: { string in
print("subscribe_3:", string)
}, onCompleted:{
print("subscribe_3: onCompleted")
}).disposed(by: disposeBag)
}

運行一下我們的測試方法 publishSubject() ,結(jié)合輸出結(jié)果來一步一步講解:
1.創(chuàng)建了一個DisposeBag
2.創(chuàng)建一個PublishSubject
3.對subject調(diào)用onNext方法,這個方法相當(dāng)于subject接受到一個.next事件,同時它會馬上把這個事件轉(zhuǎn)發(fā)給他當(dāng)前所有的訂閱者(所以說Subject即使Observable又是訂閱者)。但是此時并沒有任何訂閱subject的行為,所以你能看到上面并沒有打印出"Hello_1"這個信息。
4.我們訂閱subject,打印出.next的事件數(shù)據(jù)和.completed事件
5.再次調(diào)用subject的onNext方法,再次發(fā)出一句"Hello_2",可以看到打印"subscribe_1: Hello_2"這一句,可見我們剛剛的訂閱有作用了
6.我們再次訂閱subject,輸出用"subscribe_2"來區(qū)分標(biāo)示
7.再次調(diào)用subject的onNext方法,再次發(fā)出一句"Hello_3"。能看到兩次訂閱都打印出了"Hello_3"
8.對subject調(diào)用onCompleted方法,表示這個subject完成了,它以后再也不會發(fā)出.next事件了??梢钥吹絪ubscribe_1和subscribe_2都打印出了.competed事件。
9.再次調(diào)用subject的onNext方法,再次發(fā)出一句"Hello_4",但是你看沒有任何"Hello_4"的打印,因為subject已經(jīng)completed了,他已無法再發(fā)出.next事件了
10.我們再次訂閱subject,可以看到立刻打印了"subscribe_3: onCompleted",這表示雖然第三次訂閱是發(fā)生在subject發(fā)出.completed之后,但是第三次訂閱也能收到subject的.completed事件,告訴你我已經(jīng)結(jié)束了,別再瞎訂閱了?。?!
BehaviorSubjects
BehaviorSubject需要通過一個默認(rèn)初始值來創(chuàng)建,當(dāng)一個訂閱者來訂閱它的時候,這個訂閱者會立即收到BehaviorSubjects的上一個發(fā)出的event,之后就跟正常的情況一樣,它也會接收到BehaviorSubjects之后發(fā)出的新的event。所以它必須有初始值,不然當(dāng)它剛創(chuàng)建就有人來訂閱它的時候,它就沒有"上一個值"能用來發(fā)出了。

再上代碼和輸出結(jié)果一起來講解:
func behaviorSubject() {
// 1
let disposeBag = DisposeBag()
// 2
let subject = BehaviorSubject(value: "A")
// 3
subject.subscribe { event in
print("subscribe_1:", event)
}.disposed(by: disposeBag)
// 4
subject.onNext("B")
// 5
subject.onError(NSError(domain: "xxx", code: 0, userInfo: nil))
// 6
subject.subscribe { event in
print("subscribe_2:", event)
}.disposed(by: disposeBag)
}

記得調(diào)用一次測試方法behaviorSubject()。
1.又是先創(chuàng)建一個DisposeBag
2.創(chuàng)建一個初始值為"A"的BehaviorSubject,初始值你也可以理解為這個Subject一創(chuàng)建就調(diào)用了一個onNext方法,發(fā)出了一個值為"A"的Event
3.訂閱一次Subject,可以看到打印出了這句"subscribe_1: next(A)",雖然這個訂閱1晚于Subject"發(fā)出"A事件。但是他也能收到Subject上一個發(fā)出的值(這個例子里是它的創(chuàng)建默認(rèn)值)。
4.調(diào)用subject的onNext方法再次發(fā)出一個含有"B"的.next事件,可以看到subscribe_1也正常的打印出了
5.調(diào)用subject的onError方法,表示subject遇到一個錯誤,并且終結(jié)了,以后也不會發(fā)出.next事件了??梢钥吹絪ubscribe_1也正常打印出了這個錯誤事件
6.再次訂閱這個已經(jīng)終結(jié)的subject,可以看到subscribe_2頁打印出了Subject的錯誤,但未打印出任何.next事件值了。
ReplaySubject
ReplaySubject的關(guān)鍵就在于它在創(chuàng)建時候要給它設(shè)置一個bufferSize,這個bufferSize就表示它對于它發(fā)出過的event進(jìn)行緩存的一個數(shù)量大小。
比如一個ReplaySubjects的bufferSize設(shè)置為2,它發(fā)出了3個.next的event,那么它會將后兩個(比較新的)發(fā)出的event給緩存起來,此時如果有一個subscriber訂閱了這個ReplaySubject,那么這個subscriber就會立即收到前面緩存的兩個.next的event。
(所以上面說過的BehaviorSubject有點類似于bufferSize為1的ReplaySubject)
如果在訂閱之前,ReplaySubject就發(fā)出了.error或者.complete的event,那么此時如果一個subscriber訂閱已經(jīng)結(jié)束的ReplaySubject,除了會收到緩存的.next的event還會收到那個終結(jié)的.error或者.complete的event。
(這點是跟BehaviorSubject不同的,BehaviorSubject在終結(jié)后如果再訂閱只能收到終結(jié)的.error或者.complete,而不能收到上一個發(fā)出的.next了)
所以這個bufferSize的大小很關(guān)鍵,如果設(shè)置不當(dāng)很容易對內(nèi)存消耗產(chǎn)生很大的壓力。

上代碼示例:
func replaySubject() {
// 1
let disposeBag = DisposeBag()
// 2
let subject = ReplaySubject<String>.create(bufferSize: 2)
// 3
subject.onNext("A")
subject.onNext("B")
subject.onNext("C")
// 4
subject.subscribe { event in
print("subscribe_1:", event)
}.disposed(by: disposeBag)
// 5
subject.onNext("D")
// 6
subject.subscribe { event in
print("subscribe_2:", event)
}.disposed(by: disposeBag)
// 7
subject.onCompleted()
// 8
subject.subscribe { event in
print("subscribe_3:", event)
}.disposed(by: disposeBag)
}

還是記得調(diào)用一次上面剛寫的測試方法replaySubject()。
1.照舊創(chuàng)建一個DisposeBag
2.創(chuàng)建一個ReplaySubject,bufferSize設(shè)置為2,表示他會緩存2個發(fā)出的.next事件
3.我們調(diào)用3次subject的onNext方法,發(fā)出"A"、"B"、"C"三個值,因為我們設(shè)置了bufferSize為2,以后最后兩個event會被緩存下來
4.開始第一次的訂閱,看打印是不是輸出了"subscribe_1: next(B)"和"subscribe_1: next(C)"。這就表示這次訂閱剛發(fā)生的時候就會收到subject緩存的已發(fā)出過的event
5.再次調(diào)用subject的onNext方法發(fā)出一個"D",看打印subscribe_1也正常的接收到了這個時間。注意這個時候緩存的兩個值就從B和C變?yōu)榱薈和D
6.第二次訂閱subject看輸出確實是"subscribe_2: next(C)"和"subscribe_2: next(D)",這就驗證了subject的緩存內(nèi)容確實在不斷更新
7.調(diào)用subject的onCompleted方法,終結(jié)了這個subject。可以看到subscribe_1和subscribe_2都收到了這個完成的事件并且打印了出來
8.第三次訂閱,因為這個subject已經(jīng)終結(jié)了,所以可以看到subscribe_3除了接收并輸出了緩存的兩個事件以外還接收到了completed事件。這里需要注意的就是,跟前面的subject不同,即使subject終結(jié)了,后來的訂閱者也還是能收到已緩存的.next事件。
Variables
最后一類叫Variables,它其實是封裝了一個BehaviorSubjects,它除了具備BehaviorSubjects的功能,能夠向它的訂閱者發(fā)出上一個的event和之后新創(chuàng)建的event之外,同時還把會把當(dāng)前發(fā)出的值保存為自己的狀態(tài),正因為它是對BehaviorSubjects的封裝,所以它也必須要通過一個默認(rèn)的初始值進(jìn)行創(chuàng)建。
通俗點將就是Variables有一個value屬性,你通過改變這個value屬性的值就相當(dāng)于對一般的Subjects調(diào)用onNext()方法,而這個最新的onNext()的值就被一只保存在value屬性里了,直到你再次修改它。
但是Variables的value不能發(fā)出.error和.complete的event,即你不能給value賦值.error或者.complete,當(dāng)Variables要deallocate的時候他會自動的complete。
Variables本身沒有subscribe()方法,但是所有Subjects都有一個asObservable()方法,這個方法就會返回這個Subject的Observable類型,拿到這個Observable類型我們就能訂閱它了。
Variables之所以叫做Variables,就是在于它可以適用于多變的使用場景。比如你可以把它當(dāng)做一般的Subjects來使用,需要訂閱然后接受.next的event。你也可以在你需要查看當(dāng)前值的時候,直接去訪問Variables的value屬性,而不用去訂閱它和不斷的一直接收新event。
上代碼:
func variable() {
// 1
let disposeBag = DisposeBag()
// 2
var variable = Variable("A")
// 3
variable.value = "B"
// 4
variable.asObservable().subscribe {
print("subscribe_1:", $0)
}.disposed(by: disposeBag)
// 5
variable.value = "C"
// 6
variable.asObservable().subscribe {
print("subscribe_2:", $0)
}.disposed(by: disposeBag)
// 7
variable.value = "D"
}

調(diào)用測試方法 variable() 然后看看輸出結(jié)果,我們來一步一步講解:
1.創(chuàng)建一個DisposeBag
2.因為Variables它是對BehaviorSubjects的封裝,所以它也需要默認(rèn)初始值來創(chuàng)建,這里我們用了"A"
3.我們修改variable.value 為"B",這就相當(dāng)于對Subject調(diào)用了onNext("B")方法,此時如果有已訂閱者就可以收到.next的事件
4.通過asObservable()方法或者內(nèi)部的那個Subject,然后訂閱它,因為它具有跟BehaviorSubjects同樣的特性,所以當(dāng)一訂閱它的時候,立刻就會收到一條上一條已發(fā)出的.next事件??梢钥吹捷敵龃蛴×?subscribe_1 :next(B)"
5.再次修改value值為C,可以看到打印"subscribe_1 :next(C)",表明訂閱1收到了新的這個.next事件
6.再次進(jìn)行一次訂閱,同理會立刻收到上一條發(fā)出的.next,可見打印輸出了"subscribe_2: next(C)"
7.最后一次再修改value值為D,結(jié)果當(dāng)然就是subscribe_1和subscribe_2都收到了.next(D)的事件并且打印了出來
8.最后重點看最后兩個輸出結(jié)果,subscribe_1和subscribe_2還接收到了completed事件,這是為什么呢?因為就像上面介紹里提到的,你不能手動給Variables發(fā)送completed或者error事件來結(jié)束它,而是當(dāng)Variables要自己deallocate的時候他會自動的發(fā)出complete。因為我們這個Variable對象初始化在func variable()方法內(nèi),所以他的生命周期就被限制在了方法內(nèi),當(dāng)這個方法全部執(zhí)行完畢的時候,這個Variable對象就要被銷毀了,所以它也就自動地向它的所有訂閱者發(fā)出了completed事件。