iOS RxSwift的subject詳解

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撒遣,分別為:PublishSubjectBehaviorSubject管跺、ReplaySubject义黎、Variable。他們之間既有各自的特點豁跑,也有相同之處:

  • 首先他們都是 Observable廉涕,他們的訂閱者都能收到他們發(fā)出的新的 Event
  • 直到 Subject 發(fā)出 .complete 或者 .errorEvent 后艇拍,該 Subject 便終結(jié)了狐蜕,同時它也就不會再發(fā)出.next事件。
  • 對于那些在 Subject 終結(jié)后再訂閱他的訂閱者卸夕,也能收到 subject發(fā)出的一條 .complete.errorevent层释,告訴這個新的訂閱者它已經(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ù)欧宜。
  • 比如一個 ReplaySubjectbufferSize 設(shè)置為 2,它發(fā)出了 3 個 .nextevent拴魄,那么它會將后兩個(最近的兩個)event 給緩存起來冗茸。此時如果有一個 subscriber 訂閱了這個 ReplaySubject席镀,那么這個 subscriber 就會立即收到前面緩存的兩個.nextevent
  • 如果一個 subscriber 訂閱已經(jīng)結(jié)束的 ReplaySubject夏漱,除了會收到緩存的 .nextevent外豪诲,還會收到那個終結(jié)的 .error 或者 .completeevent

(2)時序圖

  • 最上面一條是 ReplaySubjectbufferSize 設(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ā)送 .completeevent乏梁,不需要也不能手動給 Variables 發(fā)送 completed或者 error 事件來結(jié)束它次洼。
  • 簡單地說就是 Variable 有一個 value 屬性,我們改變這個 value 屬性的值就相當于調(diào)用一般 SubjectsonNext() 方法遇骑,而這個最新的 onNext() 的值就被保存在 value 屬性里了卖毁,直到我們再次修改它。

注意
Variables 本身沒有 subscribe() 方法落萎,但是所有 Subjects 都有一個 asObservable() 方法亥啦。我們可以使用這個方法返回這個 VariableObservable 類型,拿到這個 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

RxSwift使用詳解系列
原文出自:www.hangge.com轉(zhuǎn)載請保留原文鏈接

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市绿鸣,隨后出現(xiàn)的幾起案子疚沐,更是在濱河造成了極大的恐慌,老刑警劉巖潮模,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亮蛔,死亡現(xiàn)場離奇詭異,居然都是意外死亡擎厢,警方通過查閱死者的電腦和手機究流,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進店門辣吃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人芬探,你說我怎么就攤上這事齿尽。” “怎么了灯节?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵循头,是天一觀的道長。 經(jīng)常有香客問我炎疆,道長卡骂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任形入,我火速辦了婚禮全跨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘亿遂。我一直安慰自己浓若,他們只是感情好,可當我...
    茶點故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布蛇数。 她就那樣靜靜地躺著挪钓,像睡著了一般。 火紅的嫁衣襯著肌膚如雪耳舅。 梳的紋絲不亂的頭發(fā)上碌上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機與錄音浦徊,去河邊找鬼馏予。 笑死,一個胖子當著我的面吹牛盔性,可吹牛的內(nèi)容都是我干的霞丧。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼冕香,長吁一口氣:“原來是場噩夢啊……” “哼蛹尝!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起暂筝,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤箩言,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后焕襟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡饭豹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年鸵赖,在試婚紗的時候發(fā)現(xiàn)自己被綠了务漩。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡它褪,死狀恐怖饵骨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情茫打,我是刑警寧澤居触,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站老赤,受9級特大地震影響轮洋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜抬旺,卻給世界環(huán)境...
    茶點故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一弊予、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧开财,春花似錦汉柒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至历葛,卻和暖如春斋扰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背啃洋。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工传货, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人宏娄。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓问裕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親孵坚。 傳聞我的和親對象是個殘疾皇子粮宛,可洞房花燭夜當晚...
    茶點故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容