什么是Subjects?
Subjects既可觀察也可觀察者。 他們可以接收事件并且也可以被訂閱。 Subjects接收到下一個事件,并且每次收到一個事件時,它都會轉向并將其發送到其用戶。
RxSwift有四種主題類型:
?PublishSubject:開始空,只向訂閱者發送新元素。
?BehaviorSubject:從初始值開始,并將其重新播放或新訂閱者的最新元素。
?ReplaySubject:使用緩沖區大小初始化,并將保持元素的緩沖區達到該大小,并將其重新播放給新用戶。
?Variable:包裹一個BehaviorSubject,保留當前值的狀態,并且只向 最新/初始值 重新播放新訂閱者。
1.PublishSubjects
當您只希望訂閱者從訂閱點通知新事件,直到他們取消訂閱,或者主題已被.completed或.error事件終止時,PublishSubjects便派上用場。
一個Subjects完整的工作流程分三個步驟:
第一步:創建一個Subjects
let subject = PublishSubject<String>()
第二步:訂閱
let subscriptionOne = subject.subscribe(onNext:{
string in
print(string)
})
第三步:發送消息
subject.on(.next("1"))
注意: 第三步還可以寫成subject.onNext("2")
完整的流程
let subject = PublishSubject<String>()
let subscriptionOne = subject.subscribe(onNext:{
string in
print(string)
})
subject.on(.next("1"))
subject.onNext("2")
可以把PublishSubject想象成一個郵局, subscriptionOne比成訂閱報紙的人, next比成發放報紙
在控制臺會打印1和2
下圖中, 頂行是發布主題,第二行和第三行是訂閱者。 向上箭頭表示訂閱,向下箭頭表示發出的事件。
第一個訂閱者在1)之后訂閱,所以它不會收到該事件。 但他可以收到2)和3),但是第二個用戶直到2)之后才訂閱,因此它只得到3)。
在上面的完整實例中添加第二個訂閱者
let subject = PublishSubject<String>()
let subscriptionOne = subject.subscribe(onNext:{
string in
print(string)
})
subject.on(.next("1"))
subject.onNext("2")
print("------我是分割線---------")
let subscriptionTwo = subject
.subscribe { event in
print("2)", event.element ?? event)
}
subject.onNext("3")
控制臺打印
首先, 創建了一個PublishSubject, 然后進行了第一次訂閱subscriptionOne, 訂閱完了之后發送了1和2消息, 之后又進行了第二次訂閱subscriptionTwo, 發送了3事件, 但是由于subscriptionOne在此之前也進行了訂閱, 他也會收到3的消息, 然后subscriptionTwo自己也收到了消息.
注意: 消息是由PublishSubject來發放的, 并不是subscriptionOne, 也不是subscriptionTwo. 可以把PublishSubject來比喻成一個郵局, 需要報紙的人過來訂閱每天的日報, 訂閱的順序肯定會有早有晚, subscriptionOne先來的, 他拿到了第一天和第二天的報紙, 然后第三天subscriptionTwo也來訂閱報紙, 對于郵局來說, 當第三天subscriptionTwo收到了報紙, 但是郵局同業也會把這份報紙發送給
subscriptionOne一份, 是不是這個道理.
接下里, subscriptionOne由于某種原因, 他不需要報紙了, 然后就取消了報紙的訂閱.
subscriptionOne.dispose()
執行了dispose()之后PublishSubject 會把他從自己的訂閱者管理中心把名單給刪除掉, subscriptionOne就再也不會收到消息了(再也不會收到報紙了)
但是, subscriptionTwo仍然還沒取消自己訂閱報紙的服務呀, 他仍然繼續享受著郵局的訂報服務, PublishSubject(郵局)還需要繼續發放給訂閱了報紙用戶報紙.
subject.onNext("4")
執行這句, subscriptionOne不會再收到消息, 只有subscriptionTwo能繼續收到消息.
當PublishSubject收到.completed或.error事件時,也就是停止事件,它將向以前訂閱者發出停止事件,并且不會再發出.next事件。而且, 它也將重新發布其停止事件給未來的訂閱者。
添加下面的代碼在上面示例的最下面
// 1
subject.onCompleted()
// 2
subject.onNext("5")
// 3
subscriptionTwo.dispose()
let disposeBag = DisposeBag()
// 4
subject.subscribe {
print("3)", $0.element ?? $0)
}.addDisposableTo(disposeBag)
subject.onNext("?"
- 執行subject.onCompleted(), 訂閱將被停止
- 再執行next事件,將不會收到消息, 但是會收到completed事件
- 當一個訂閱被廢棄之后, 別忘記進行銷毀
- 使用DisposeBag的方式再次進行訂閱, 此時我們的訂閱不會收到任何消息, 但是會收到一個completed事件, 告訴我們, 我們訂閱的對象已經被銷毀了.
2.BehaviorSubjects
BehaviorSubjects類似于PublishSubjects,除了他們將重新發送最新的.next事件給新訂閱者。
頂部的第一行是主題。 第二行上的第一個訂戶在1)之后但在2)之前訂閱,所以它在訂閱后立即獲得1),然后2)和3)當它們被主題發出時。 類似地,第二用戶在2)之后但在3之前訂閱,所以它立即得到2)然后3)當它被發射時。
let subject = BehaviorSubject(value: "Initial value")
let disposeBag = DisposeBag()
subject.subscribe {
print(label: "1)", event: $0)
}.addDisposableTo(disposeBag)
BehaviorSubject會有一個初始值, 當被訂閱之后, 會默認先打印默認值
添加一個消息
let subject = BehaviorSubject(value: "Initial value")
let disposeBag = DisposeBag()
//添加一個消息
subject.onNext("X")
subject.subscribe {
print(label: "1)", event: $0)
}.addDisposableTo(disposeBag)
在PublishSubjects中, 我們是需要先訂閱然后在發送消息才能收到消息, 這樣寫是收不到消息的
let subject = PublishSubject<String>()
subject.on(.next("在訂閱之前的消息將不會收到"))
let subscriptionOne = subject.subscribe(onNext:{
string in
print(string)
})
但是在BehaviorSubject中, 目前來看是可以收到消息的
當您想使用最新數據預先填充視圖時,行為主題很有用。 例如,您可以將用戶配置文件屏幕中的控件綁定到行為主題,以便最新的值可用于在應用程序獲取新數據時預先填充顯示。
3.ReplaySubjects
ReplaySubjects將臨時緩存或緩沖其發射的最新元素,達到您選擇的指定大小。 然后,它會將該緩沖區重播給新的訂閱者。 以下大理石圖描繪了緩沖區大小為2的重播主題。 第一個用戶(中間行)已經訂閱了重播主題(頂行),因此它們在發出時獲取元素。 第二個用戶(底線)在2)之后訂閱,所以它得到1)和2)重播。
// 1
let subject = ReplaySubject<String>.create(bufferSize: 2)
let disposeBag = DisposeBag()
// 2
subject.onNext("1")
subject.onNext("2")
subject.onNext("3")
// 3
subject.subscribe {
print(label: "1)", event: $0)
}.addDisposableTo(disposeBag)
subject.subscribe {
print(label: "2)", event: $0)
}.addDisposableTo(disposeBag)
在上面的示例中只有2和3被打印, 因為緩沖區大小為2, ReplaySubject會保留最新的兩個值
再添加一個訂閱
print("----------")
subject.onNext("4")
subject.subscribe {
print(label: "3)", event: $0)
}.addDisposableTo(disposeBag)
前兩個訂閱將會正常打印, 并打印了發出的消息4, 但是對于第三個訂閱, 他會重新的打印緩沖區中最新的兩個值
4.Variables
如前所述,Variable包含一個BehaviorSubject并將其當前值存儲為狀態。 您可以通過其value屬性訪問當前值,并且與其他主題和可觀察器通常不同,您還可以使用該value屬性將新元素設置到變量上。 換句話說,你不要使用onNext(_ :)。
因為它包裹一個行為主體,所以創建一個具有初始值的變量,并且它會將新的或最初的值重播到新的訂閱者。 為了訪問一個變量的底層行為主體,你調用asObservable()就可以了。
與其他科目相比,變量也是唯一的,就是保證不會發出錯誤。 因此,盡管您可以在對變量的訂閱中偵聽.error事件,但是您不能將.error事件添加到變量中。 一個變量也將在即將被釋放的時候自動完成,所以你不(并且實際上不能)手動添加一個.completed事件。
// 1
var variable = Variable("Initial value")
let disposeBag = DisposeBag()
// 2
variable.value = "New initial value"
// 3
variable.asObservable().subscribe {
print(label: "1)", event: $0)
}.addDisposableTo(disposeBag)
- 創建一個Variable, Variable變量的類型是被推斷的, 但是你也可以給他一個明確的類型
Variable<String>("Initial value")
- 添加一個新的值給variable
3.訂閱variable, 首先需要通過asObservable()獲取BehaviorSubject
添加新的訂閱
// 1
variable.value = "1"
// 2
variable.asObservable().subscribe {
print(label: "2)", event: $0)
}.addDisposableTo(disposeBag)
// 3
variable.value = "2"
- 添加一個新的值
- 添加一個新的訂閱
- 添加另外一個新的值
控制臺會打印
1) 1
2) 1
1) 2
2) 2
對于以上4種類型的具體使用場景可能現在感覺不是很熟悉, 我現在也是不是很熟悉, 正在具體查看這方面的資料.