Subjects 介紹
- 從前面的幾篇文章可以發(fā)現(xiàn)膏燃,當我們創(chuàng)建一個
Observable
的時候就要預(yù)先將要發(fā)出的數(shù)據(jù)都準備好邓线,等到有人訂閱它時再將數(shù)據(jù)通過Event
發(fā)出去仪糖。- 但有時我們希望
Observable
在運行時能動態(tài)地“獲得”或者說“產(chǎn)生”出一個新的數(shù)據(jù)刃麸,再通過Event
發(fā)送出去垃环。比如:訂閱一個輸入框的輸入內(nèi)容坯门,當用戶每輸入一個字后,這個輸入框關(guān)聯(lián)的Observable
就會發(fā)出一個帶有輸入內(nèi)容的Event
挡闰,通知給所有訂閱者乒融。- 這個就可以使用下面將要介紹的
Subjects
來實現(xiàn)。
1摄悯,Subjects 基本介紹
(1)Subjects
既是訂閱者赞季,也是 Observable
:
- 說它是訂閱者,是因為它能夠動態(tài)地接收新的值奢驯。
- 說它又是一個
Observable
申钩,是因為當Subjects
有了新的值之后,就會通過Event
將新值發(fā)出給他的所有訂閱者瘪阁。
(2)一共有四種 Subjects
撒遣,分別為:PublishSubject
、BehaviorSubject
管跺、ReplaySubject
义黎、Variable
。他們之間既有各自的特點豁跑,也有相同之處:
- 首先他們都是
Observable
廉涕,他們的訂閱者都能收到他們發(fā)出的新的Event
。 - 直到
Subject
發(fā)出.complete
或者.error
的Event
后艇拍,該Subject
便終結(jié)了狐蜕,同時它也就不會再發(fā)出.next
事件。 - 對于那些在
Subject
終結(jié)后再訂閱他的訂閱者卸夕,也能收到subject
發(fā)出的一條.complete
或.error
的event
层释,告訴這個新的訂閱者它已經(jīng)終結(jié)了。 - 他們之間最大的區(qū)別只是在于:當一個新的訂閱者剛訂閱它的時候娇哆,能不能收到
Subject
以前發(fā)出過的舊Event
湃累,如果能的話又能收到多少個勃救。
(3)Subject 常用的幾個方法:
-
onNext(:):是
on(.next(:))
的簡便寫法。該方法相當于subject
接收到一個.next
事件治力。 -
onError(:):是
on(.error(:))
的簡便寫法蒙秒。該方法相當于subject
接收到一個.error
事件。 -
onCompleted():是
on(.completed)
的簡便寫法宵统。該方法相當于subject
接收到一個.completed
事件晕讲。
2,PublishSubject
(1)基本介紹
-
PublishSubject
是最普通的Subject
马澈,它不需要初始值就能創(chuàng)建瓢省。 -
PublishSubject
的訂閱者從他們開始訂閱的時間點起,可以收到訂閱后Subject
發(fā)出的新Event
痊班,而不會收到他們在訂閱前已發(fā)出的Event
勤婚。
(2)時序圖
- 最上面一條是
PublishSubject
。 - 下面兩條分別表示兩個新的訂閱涤伐,它們訂閱的時間點不同馒胆,可以發(fā)現(xiàn)
PublishSubject
的訂閱者只能收到他們訂閱后的Event
。
image
(3)使用樣例
let disposeBag = DisposeBag()
//創(chuàng)建一個PublishSubject
let subject = PublishSubject<String>()
//由于當前沒有任何訂閱者凝果,所以這條信息不會輸出到控制臺
subject.onNext("111")
//第1次訂閱subject
subject.subscribe(onNext: { string in
print("第1次訂閱:", string)
}, onCompleted:{
print("第1次訂閱:onCompleted")
}).disposed(by: disposeBag)
//當前有1個訂閱祝迂,則該信息會輸出到控制臺
subject.onNext("222")
//第2次訂閱subject
subject.subscribe(onNext: { string in
print("第2次訂閱:", string)
}, onCompleted:{
print("第2次訂閱:onCompleted")
}).disposed(by: disposeBag)
//當前有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)
運行結(jié)果如下:
image
3山害,BehaviorSubject
(1)基本介紹
-
BehaviorSubject
需要通過一個默認初始值來創(chuàng)建纠俭。 - 當一個訂閱者來訂閱它的時候,這個訂閱者會立即收到
BehaviorSubjects
上一個發(fā)出的event
粗恢。之后就跟正常的情況一樣柑晒,它也會接收到BehaviorSubject
之后發(fā)出的新的event
欧瘪。
(2)時序圖
- 最上面一條是
BehaviorSubject
眷射。 - 下面兩條分別表示兩個新的訂閱,它們訂閱的時間點不同佛掖,可以發(fā)現(xiàn)
BehaviorSubject
的訂閱者一開始就能收到BehaviorSubjects
之前發(fā)出的一個Event
妖碉。
image
]
(3)使用樣例
let disposeBag = DisposeBag()
//創(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)
運行結(jié)果如下:
image
4,ReplaySubject
(1)基本介紹
-
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
。
(2)時序圖
- 最上面一條是
ReplaySubject
(bufferSize
設(shè)為為 2)挂绰。 - 下面兩條分別表示兩個新的訂閱屎篱,它們訂閱的時間點不同】伲可以發(fā)現(xiàn)
ReplaySubject
的訂閱者一開始就能收到ReplaySubject
之前發(fā)出的兩個Event
(如果有的話)交播。
image
(3)使用樣例
let disposeBag = DisposeBag()
//創(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)
運行結(jié)果如下:
image
5,Variable
(1)基本介紹
-
Variable
其實就是對BehaviorSubject
的封裝践付,所以它也必須要通過一個默認的初始值進行創(chuàng)建秦士。 -
Variable
具有BehaviorSubject
的功能,能夠向它的訂閱者發(fā)出上一個event
以及之后新創(chuàng)建的event
永高。 - 不同的是伍宦,
Variable
還會把當前發(fā)出的值保存為自己的狀態(tài)。同時它會在銷毀時自動發(fā)送.complete
的event
乏梁,不需要也不能手動給Variables
發(fā)送completed
或者error
事件來結(jié)束它次洼。 - 簡單地說就是
Variable
有一個value
屬性,我們改變這個value
屬性的值就相當于調(diào)用一般Subjects
的onNext()
方法遇骑,而這個最新的onNext()
的值就被保存在value
屬性里了卖毁,直到我們再次修改它。
注意:
Variables
本身沒有subscribe()
方法落萎,但是所有Subjects
都有一個asObservable()
方法亥啦。我們可以使用這個方法返回這個Variable
的Observable
類型,拿到這個Observable
類型我們就能訂閱它了练链。
(2)使用樣例
import UIKit
import RxSwift
import RxCocoa
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let disposeBag = DisposeBag()
//創(chuàng)建一個初始值為111的Variable
let variable = Variable("111")
//修改value值
variable.value = "222"
//第1次訂閱
variable.asObservable().subscribe {
print("第1次訂閱:", $0)
}.disposed(by: disposeBag)
//修改value值
variable.value = "333"
//第2次訂閱
variable.asObservable().subscribe {
print("第2次訂閱:", $0)
}.disposed(by: disposeBag)
//修改value值
variable.value = "444"
}
}
運行結(jié)果如下:
注意:由于
Variable
對象在viewDidLoad()
方法內(nèi)初始化翔脱,所以它的生命周期就被限制在該方法內(nèi)。當這個方法執(zhí)行完畢后媒鼓,這個Variable
對象就會被銷毀届吁,同時它也就自動地向它的所有訂閱者發(fā)出.completed
事件
image