RxSwift - Subjects(2)

Rx_Logo_M-320x320.png

什么是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

下圖中, 頂行是發布主題,第二行和第三行是訂閱者。 向上箭頭表示訂閱,向下箭頭表示發出的事件。


屏幕快照 2017-08-13 上午10.03.31.png

第一個訂閱者在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("?"
  1. 執行subject.onCompleted(), 訂閱將被停止
  2. 再執行next事件,將不會收到消息, 但是會收到completed事件
  3. 當一個訂閱被廢棄之后, 別忘記進行銷毀
  4. 使用DisposeBag的方式再次進行訂閱, 此時我們的訂閱不會收到任何消息, 但是會收到一個completed事件, 告訴我們, 我們訂閱的對象已經被銷毀了.

2.BehaviorSubjects

BehaviorSubjects類似于PublishSubjects,除了他們將重新發送最新的.next事件給新訂閱者。

屏幕快照 2017-08-13 上午11.42.11.png

頂部的第一行是主題。 第二行上的第一個訂戶在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)重播。

屏幕快照 2017-08-13 下午1.21.53.png
    // 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)
屏幕快照 2017-08-13 下午1.32.15.png

前兩個訂閱將會正常打印, 并打印了發出的消息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)
  1. 創建一個Variable, Variable變量的類型是被推斷的, 但是你也可以給他一個明確的類型Variable<String>("Initial value")
  2. 添加一個新的值給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. 添加一個新的值
  2. 添加一個新的訂閱
  3. 添加另外一個新的值

控制臺會打印

1) 1
2) 1
1) 2
2) 2

對于以上4種類型的具體使用場景可能現在感覺不是很熟悉, 我現在也是不是很熟悉, 正在具體查看這方面的資料.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,702評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,143評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,553評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,620評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,416評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,940評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,024評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,170評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,709評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,597評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,291評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,029評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,407評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,663評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,403評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,746評論 2 370

推薦閱讀更多精彩內容