RxSwift介紹(三)——更加靈活的Subject

前一篇文章講述 RxSwift 框架中最重要的類 Observable<T> ,但是其局限性只能作為被訂閱者被動接收信號并響應(yīng)事件。項(xiàng)目中避免不了主動發(fā)出信號操作的情況,這時(shí)就需要 Subject 類來完成。與之前RAC框架中的 Subject 類功能非常相似,既能攻也能受啃奴,是不僅可以成為可觀察對象被動接受事件潭陪,還可以成為觀察者主動發(fā)送事件。

Subject 其訂閱者也是 Observable最蕾,首先可以動態(tài)地接受新值依溯,其次當(dāng) subject 值更新時(shí),會通過 event 把新值發(fā)送給所有的訂閱者瘟则。

在 RxSwift 框架中黎炉,提供了四種類型的 subject,首先要了解的一點(diǎn)就是提供的四種 subject 創(chuàng)建方式最主要的區(qū)別:當(dāng)一個(gè)新的訂閱者訂閱到subject對象時(shí)醋拧,能否收到 subject 以前發(fā)出過的舊 event慷嗜,如果能,接收的數(shù)量又有不同丹壕。

  1. PublishSubject 最普通的 subject 庆械,不需要初始值就可以創(chuàng)建,而且從訂閱者開始訂閱的時(shí)間點(diǎn)起菌赖,可以收到 subject 發(fā)出的新 event缭乘,而不會收到在訂閱前已發(fā)出的 event
  2. BehaviorSubject 當(dāng)訂閱者訂閱 subject 時(shí),會立即收到 BehaviorSubject 上一個(gè)發(fā)出的 event琉用,之后與 PublishSubject 功能相同
  3. ReplaySubject 除了包含 PublishSubject 的功能堕绩,還可以手動設(shè)置訂閱者接收到舊的 event 個(gè)數(shù)。因此邑时,在使用時(shí)必須在創(chuàng)建時(shí)設(shè)置 bufferSize奴紧,表示將會返回給訂閱者對應(yīng)個(gè)數(shù)最近緩存的舊 event
    (注:若一個(gè)訂閱者去訂閱已經(jīng)結(jié)束的 ReplaySubject ,除了會收到緩存的 .next 的 event之外晶丘,還會收到終結(jié)該 ReplaySubject 的 .error 或 .completed 的event)
    在實(shí)際開發(fā)過程中绰寞,ReplaySubject 緩存機(jī)制使用了數(shù)組結(jié)構(gòu),所以當(dāng)有大量 ReplaySubject 對象時(shí)可能導(dǎo)致內(nèi)存暴增。另外滤钱,如果緩存對象是圖片觉壶、視頻等極耗內(nèi)存的資源時(shí)也可能導(dǎo)致內(nèi)存問題。所以 ReplaySubject 不可濫用且緩存區(qū)大小必須合理進(jìn)行設(shè)置件缸,必要時(shí)可手動進(jìn)行釋放管理
  4. Variable 本身是對 BehaviorSubject 封裝铜靶,創(chuàng)建時(shí)也必須設(shè)置一個(gè)默認(rèn)值。繼承自 BehaviorSubject 他炊,那么就能向訂閱者發(fā)出上一個(gè) event 與新的 event争剿。與 BehaviorSubject 不同的是,Variable還會把當(dāng)前發(fā)出的值保存為自己的狀態(tài)痊末,同時(shí)在銷毀時(shí)自動發(fā)送 .completed event蚕苇,不需要也不能手動給 Variable 發(fā)送終結(jié)事件 .completed 或 .error 來終結(jié)。
    換個(gè)方式理解凿叠,Variable 有一個(gè) value 屬性涩笤,當(dāng)改變 value 屬性的值時(shí)就相當(dāng)于調(diào)用一般 Subjects 的 onNext() 方法,而這個(gè)最新的 onNext() 的值就被保存在 value 屬性里盒件,直到再次修改 value
    (注:Variable 本身沒有提供 subscribe() 方法蹬碧,但是所有 Subjects 都有一個(gè) asObservable() 方法〕吹螅可以使用這個(gè)方法返回這個(gè) Variable 的 Observable 類型恩沽,拿到這個(gè) Observable 類型就能訂閱它了)

介紹了以上四種 subject ,接下來貼代碼并附上運(yùn)行打印截圖翔始,有興趣的可以copy下來運(yùn)行一遍罗心,了解其 event 執(zhí)行順序

PublishSubject代碼示例

        let subject = PublishSubject<String>()
        subject.onNext("first signal")
        subject.subscribe(onNext: { (event) in
            print("first event is"+event)
        }, onCompleted: {
            print("completed first")
        }) {
            print("first :銷毀了")
        }.disposed(by: disposeB)
        
        subject.onNext("second signal")
        subject.subscribe(onNext: { (event) in
            print("second event is "+event)
        }, onCompleted: {
            print("completed second")
        }) {
            print("second :銷毀了")
        }.disposed(by: disposeB)
        
        //讓subject結(jié)束,后面再進(jìn)行訂閱
        subject.onCompleted()
        
        subject.onNext("third signal")
        subject.onNext("fourth signal")
        subject.subscribe(onNext: { (event) in
            print("this is another"+event)
        }, onCompleted: {
            print("completed another")
        }) {
            print("another :銷毀了")
        }.disposed(by: disposeB)
PublishSubject打印結(jié)果

BehaviorSubject代碼示例

        let subject = BehaviorSubject(value: "first signal")
        subject.onNext("another first signal") //會替換了 first signal 的信號
        subject.subscribe(onNext: { (event) in
            print(event)
        } , onCompleted: {
            print("completed")
        }) {
            print("第一個(gè)銷毀了")
        }.disposed(by: disposeB)
        
        subject.onNext("second signal")

        subject.onNext("third signal") //這里試圖替換上面的 second signal 的event
        subject.subscribe(onNext: { (event) in
            print(event)
        } , onCompleted: {
            print("completed")
        }) {
            print("第二個(gè)銷毀了")
        }.disposed(by: disposeB)
        
        subject.onError(NSError(domain: "myError", code: 10010, userInfo: ["myUserInfo":"10010錯(cuò)誤"]))
BehaviorSubject打印結(jié)果

ReplaySubject代碼示例

        //設(shè)置緩存最近2個(gè)event
        let subject = ReplaySubject<String>.create(bufferSize: 2)
        subject.onNext("first")
        subject.onNext("second")
        subject.onNext("third")

        subject.subscribe(onNext: { (event) in
            print(event)
        }, onError: { (error) in
            print(error)
        }, onCompleted: {
            print("這是一個(gè) 完成")
        }) {
            print("銷毀了")
        }.disposed(by: disposeB)

        subject.onCompleted()//現(xiàn)在終結(jié)subject
        
        subject.subscribe(onNext: { (event) in
            print(event)
        }, onError: { (error) in
            print(error)
        }, onCompleted: {
            print("完成之后的訂閱完成")
        }) {
            print("完成之后銷毀了")
        }.disposed(by: disposeB)
ReplaySubject打印結(jié)果

Variable代碼示例

        let subject = Variable("first")
        subject.value = "second"
        subject.asObservable().subscribe(onNext: { (event) in
            print(event)
        }, onError: { (error) in
            print(error)
        }, onCompleted: {
            print("Variber訂閱完成")
        }) {
            print("Variber銷毀")
        }
        .disposed(by: disposeB)
        
        subject.value = "third"

Variable打印結(jié)果

打印結(jié)果中給出了一個(gè)警告,在其GitHub的issue鏈接中城瞎,提到了 Variable 要在接下來的版本里刪除协屡,請用 BehaviorRelay 代替,其實(shí) Variable 封裝全谤,還是比較順手肤晓。貌似現(xiàn)在UI層的很多都是 Variable 來管理,但 RxSwift 也封裝了很多關(guān)于UI的认然,issue的回復(fù)中說以后會銷毀补憾,注意是銷毀 Variable 這個(gè)類。


該文章首次發(fā)表在 簡書:我只不過是出來寫寫代碼 博客卷员,并自動同步至 騰訊云:我只不過是出來寫寫iOS 博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盈匾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子毕骡,更是在濱河造成了極大的恐慌削饵,老刑警劉巖岩瘦,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異窿撬,居然都是意外死亡启昧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門劈伴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來密末,“玉大人,你說我怎么就攤上這事跛璧⊙侠铮” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵追城,是天一觀的道長刹碾。 經(jīng)常有香客問我,道長座柱,這世上最難降的妖魔是什么迷帜? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮辆布,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘茶鉴。我一直安慰自己锋玲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布涵叮。 她就那樣靜靜地躺著惭蹂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪割粮。 梳的紋絲不亂的頭發(fā)上盾碗,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天,我揣著相機(jī)與錄音舀瓢,去河邊找鬼廷雅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛京髓,可吹牛的內(nèi)容都是我干的航缀。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼堰怨,長吁一口氣:“原來是場噩夢啊……” “哼芥玉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起备图,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤灿巧,失蹤者是張志新(化名)和其女友劉穎赶袄,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抠藕,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡饿肺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了幢痘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唬格。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖颜说,靈堂內(nèi)的尸體忽然破棺而出购岗,到底是詐尸還是另有隱情,我是刑警寧澤门粪,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布喊积,位于F島的核電站,受9級特大地震影響玄妈,放射性物質(zhì)發(fā)生泄漏乾吻。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一拟蜻、第九天 我趴在偏房一處隱蔽的房頂上張望绎签。 院中可真熱鬧,春花似錦酝锅、人聲如沸诡必。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽爸舒。三九已至,卻和暖如春稿蹲,著一層夾襖步出監(jiān)牢的瞬間扭勉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工苛聘, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涂炎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓设哗,卻偏偏與公主長得像璧尸,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子熬拒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

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