RxSwift(六)-- RxSwift使用介紹Subject

Subject介紹

從之前的文章RxSwift(三)-- RxSwift使用介紹Observable的創(chuàng)建中奕删,我們可以知道拄氯,當(dāng)我們需要?jiǎng)?chuàng)建一個(gè) Observable的時(shí)候,要預(yù)先將要發(fā)出的數(shù)據(jù)都準(zhǔn)備好满俗,等到有人訂閱它時(shí)再將數(shù)據(jù)通過 Event發(fā)出去菩鲜。
不過,有時(shí)我們也希望 Observable 在運(yùn)行時(shí)能動(dòng)態(tài)地“獲得”或者說“產(chǎn)生”出一個(gè)新的數(shù)據(jù)胳螟,再通過 Event 發(fā)送出去昔馋。比如:訂閱一個(gè)輸入框的輸入內(nèi)容,當(dāng)用戶每輸入一個(gè)字后糖耸,這個(gè)輸入框關(guān)聯(lián)的 Observable 就會(huì)發(fā)出一個(gè)帶有輸入內(nèi)容的 Event秘遏,通知給所有訂閱者。
這個(gè)時(shí)候嘉竟,我們要介紹的Subject就登場了邦危。

Subject基本介紹

  1. Subject它既是訂閱者洋侨,也是Observable序列:
  • 因?yàn)樗軌騽?dòng)態(tài)地接收新的值,所以它是訂閱者倦蚪。
  • 因?yàn)?code>Subject有了新的值以后希坚,會(huì)通過Event事件將新的值發(fā)出來給到訂閱者,所以它又是一個(gè)Observable序列陵且。
  1. RxSwiftSubject的分類是:PublishSubject裁僧、BehaviorSubjectReplaySubject慕购、AsyncSubject锅知、BehaviorRelay,它們之間既有各自的特點(diǎn)脓钾,也有相同之處:
  • 它們都是Observable序列售睹,訂閱者都能收到它們發(fā)出的新的Event
  • 等到Subject發(fā)出.complete或者.errorEvent可训,Subject也就結(jié)束了昌妹,也就不會(huì)再發(fā)出.next事件了。
  • 如果在Subject結(jié)束后再訂閱的訂閱者握截,也可以收到Subject發(fā)出的一條.complete或者.error事件飞崖,用來告訴訂閱者已經(jīng)結(jié)束了。
  • 它們之間的最大區(qū)別是:當(dāng)一個(gè)新的訂閱者剛訂閱它的時(shí)候谨胞,能不能收到 Subject 以前發(fā)出過的舊 Event固歪,如果能的話又能收到多少個(gè)。
  1. Subject的常用方法:
  • onNext(:):是 on(.next(:)) 的簡便寫法胯努。該方法相當(dāng)于 Subject 接收到一個(gè) .next 事件牢裳。
  • onError(:):是 on(.error(:)) 的簡便寫法。該方法相當(dāng)于 Subject 接收到一個(gè) .error 事件叶沛。
  • onCompleted():是 on(.completed) 的簡便寫法蒲讯。該方法相當(dāng)于 subject 接收到一個(gè) .completed 事件。

PublishSubject

  1. 介紹
  • PublishSubject不需要初始值就能創(chuàng)建(也就是可以為空)灰署。
  • PublishSubject的訂閱者從他們開始訂閱的時(shí)間點(diǎn)起判帮,可以收到訂閱后 Subject 發(fā)出的新 Event事件,而不會(huì)收到他們在訂閱前已發(fā)出的 Event事件溉箕。
  1. 代碼展示
// 創(chuàng)建一個(gè)PublishSubject
        let subject = PublishSubject<String>()
        
        // 由于當(dāng)前沒有任何訂閱者晦墙,所以這條信息不會(huì)輸出到控制臺(tái)
        subject.onNext("111")
        
        // 第1次訂閱subject
        subject.subscribe(onNext: { string in
            print("第1次訂閱:", string)
        }, onCompleted:{
            print("第1次訂閱:onCompleted")
        }).disposed(by: disposeBag)
        
        // 當(dāng)前有1個(gè)訂閱,則該信息會(huì)輸出到控制臺(tái)
        subject.onNext("222")
       
        // 第2次訂閱subject
        subject.subscribe(onNext: { string in
            print("第2次訂閱:", string)
        }, onCompleted:{
            print("第2次訂閱:onCompleted")
        }).disposed(by: disposeBag)
        
        // 當(dāng)前有2個(gè)訂閱肴茄,則該信息會(huì)輸出到控制臺(tái)
        subject.onNext("333")
        
        // 讓subject結(jié)束
        subject.onCompleted()
        
        // subject完成后會(huì)發(fā)出.next事件了晌畅。
        subject.onNext("444")
        // subject完成后它的所有訂閱(包括結(jié)束后的訂閱),都能收到subject的.completed事件独郎,
        subject.subscribe(onNext: { string in
            print("第3次訂閱:", string)
        }, onCompleted:{
            print("第3次訂閱:onCompleted")
        }).disposed(by: disposeBag)

運(yùn)行結(jié)果:

第1次訂閱: 222
第1次訂閱: 333
第2次訂閱: 333
第1次訂閱:onCompleted
第2次訂閱:onCompleted
第3次訂閱:onCompleted

BehaviorSubject

  1. 介紹
  • BehaviorSubject 需要通過一個(gè)默認(rèn)初始值來創(chuàng)建踩麦。
  • 當(dāng)一個(gè)訂閱者來訂閱它的時(shí)候枚赡,這個(gè)訂閱者會(huì)立即收到 BehaviorSubjects 上一個(gè)發(fā)出的 event事件,如果還沒有收到任何數(shù)據(jù)谓谦,則會(huì)發(fā)出一個(gè)默認(rèn)值贫橙。之后就跟PublishSubject正常的情況一樣,它也會(huì)接收到 BehaviorSubject 之后發(fā)出的新的 event事件反粥。
  1. 代碼展示
// 創(chuàng)建一個(gè)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)

運(yùn)行結(jié)果:

第1次訂閱: next(111)
第1次訂閱: next(222)
第1次訂閱: error(Error Domain=local Code=0 "(null)")
第2次訂閱: error(Error Domain=local Code=0 "(null)")

ReplaySubject

  1. 介紹
  • ReplaySubject 在創(chuàng)建時(shí)候需要設(shè)置一個(gè) bufferSize卢肃,表示它對(duì)于它發(fā)送過的 event 的緩存?zhèn)€數(shù)。
  • 比如一個(gè) ReplaySubjectbufferSize 設(shè)置為 2才顿,它發(fā)出了 3 個(gè) .nextevent莫湘,那么它會(huì)將后兩個(gè)(最近的兩個(gè))event 給緩存起來。此時(shí)如果有一個(gè) subscriber 訂閱了這個(gè) ReplaySubject郑气,那么這個(gè) subscriber 就會(huì)立即收到前面緩存的兩個(gè) .nextevent幅垮。
  • 如果一個(gè) subscriber 訂閱已經(jīng)結(jié)束的 ReplaySubject,除了會(huì)收到緩存的 .nextevent 外尾组,還會(huì)收到那個(gè)終結(jié)的 .error 或者 .completeevent忙芒。
  1. 代碼展示
//創(chuàng)建一個(gè)bufferSize為2的ReplaySubject
        let subject = ReplaySubject<String>.create(bufferSize: 2)
        
        //連續(xù)發(fā)送3個(gè)next事件
        subject.onNext("111")
        subject.onNext("222")
        subject.onNext("333")
        
        //第1次訂閱subject
        subject.subscribe { event in
            print("第1次訂閱:", event)
            }.disposed(by: disposeBag)
        
        //再發(fā)送1個(gè)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)

運(yùn)行結(jié)果:

第1次訂閱: next(222)
第1次訂閱: next(333)
第1次訂閱: next(444)
第2次訂閱: next(333)
第2次訂閱: next(444)
第1次訂閱: completed
第2次訂閱: completed
第3次訂閱: next(333)
第3次訂閱: next(444)
第3次訂閱: completed

BehaviorRelay

  1. 介紹
  • BehaviorRelay 是作為 Variable 的替代者出現(xiàn)的。它的本質(zhì)其實(shí)也是對(duì) BehaviorSubject 的封裝讳侨,所以它也必須要通過一個(gè)默認(rèn)的初始值進(jìn)行創(chuàng)建呵萨。
  • BehaviorRelay 具有 BehaviorSubject 的功能,能夠向它的訂閱者發(fā)出上一個(gè) event 以及之后新創(chuàng)建的 event跨跨。
  • BehaviorSubject 不同的是潮峦,不需要也不能手動(dòng)給 BehaviorReply 發(fā)送 completed 或者 error 事件來結(jié)束它(BehaviorRelay 在銷毀時(shí)也不會(huì)自動(dòng)發(fā)送 .completeevent)。
  • BehaviorRelay 有一個(gè) value屬性勇婴,我們通過這個(gè)屬性可以獲取最新值忱嘹。而通過它的 accept() 方法可以對(duì)值進(jìn)行修改。
  1. 代碼展示
//創(chuàng)建一個(gè)初始值為111的BehaviorRelay
        let subject = BehaviorRelay<String>(value: "111")
        
        //修改value值
        subject.accept("222")
        
        //第1次訂閱
        subject.asObservable().subscribe {
            print("第1次訂閱:", $0)
            }.disposed(by: disposeBag)
        
        //修改value值
        subject.accept("333")
        
        //第2次訂閱
        subject.asObservable().subscribe {
            print("第2次訂閱:", $0)
            }.disposed(by: disposeBag)
        
        //修改value值
        subject.accept("444")

運(yùn)行結(jié)果:

第1次訂閱: next(222)
第1次訂閱: next(333)
第2次訂閱: next(333)
第1次訂閱: next(444)
第2次訂閱: next(444)
  1. 另外咆耿,如果想將新值合并到原值上德谅,可以通過 accept() 方法與 value 屬性配合來實(shí)現(xiàn)爹橱。(這個(gè)常用在表格上拉加載功能上萨螺,BehaviorRelay 用來保存所有加載到的數(shù)據(jù))
//創(chuàng)建一個(gè)初始值為包含一個(gè)元素的數(shù)組的BehaviorRelay
        let subject = BehaviorRelay<[String]>(value: ["1"])
        
        //修改value值
        subject.accept(subject.value + ["2", "3"])
        
        //第1次訂閱
        subject.asObservable().subscribe {
            print("第1次訂閱:", $0)
            }.disposed(by: disposeBag)
        
        //修改value值
        subject.accept(subject.value + ["4", "5"])
        
        //第2次訂閱
        subject.asObservable().subscribe {
            print("第2次訂閱:", $0)
            }.disposed(by: disposeBag)
        
        //修改value值
        subject.accept(subject.value + ["6", "7"])

運(yùn)行結(jié)果:

第1次訂閱: next(["1", "2", "3"])
第1次訂閱: next(["1", "2", "3", "4", "5"])
第2次訂閱: next(["1", "2", "3", "4", "5"])
第1次訂閱: next(["1", "2", "3", "4", "5", "6", "7"])
第2次訂閱: next(["1", "2", "3", "4", "5", "6", "7"])

AsyncSubject

  1. 介紹
  • 一個(gè)AsyncSubject只在原始Observable完成后,發(fā)射來自原始Observable的最后一個(gè)值愧驱。
  • 如果原始Observable沒有發(fā)射任何值慰技,AsyncObject也不發(fā)射任何值,它會(huì)把這最后一個(gè)值發(fā)射給任何后續(xù)的觀察者组砚。
  • 如果原始的Observable因?yàn)榘l(fā)生了錯(cuò)誤而終止吻商,AsyncSubject將不會(huì)發(fā)射任何數(shù)據(jù),只是簡單的向前傳遞這個(gè)錯(cuò)誤通知糟红。
  1. 代碼展示
let subject = AsyncSubject<Int>()
        
        subject.onNext(1)
        
        subject.subscribe(onNext: { int in
            print("observerA: \(int)")
        }, onCompleted: {
            print("observerA: onCompleted")
        }).disposed(by: disposeBag)
        
        subject.onNext(2)
        
        subject.subscribe(onNext: { int in
            print("observerB: \(int)")
        }, onCompleted: {
            print("observerB: onCompleted")
        }).disposed(by: disposeBag)
        
        subject.onNext(3)
        
        subject.subscribe(onNext: { int in
            print("observerC: \(int)")
        }, onCompleted: {
            print("observerC: onCompleted")
        }).disposed(by: disposeBag)
        
        subject.onCompleted()
        
        subject.onNext(4)
        
        subject.subscribe(onNext: { int in
            print("observerD: \(int)")
        }, onCompleted: {
            print("observerD: onCompleted")
        }).disposed(by: disposeBag)

運(yùn)行結(jié)果:

observerA: 3
observerB: 3
observerC: 3
observerA: onCompleted
observerB: onCompleted
observerC: onCompleted
observerD: 3
observerD: onCompleted
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末艾帐,一起剝皮案震驚了整個(gè)濱河市乌叶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌柒爸,老刑警劉巖准浴,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異捎稚,居然都是意外死亡乐横,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門今野,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葡公,“玉大人,你說我怎么就攤上這事条霜〈呤玻” “怎么了?”我有些...
    開封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵宰睡,是天一觀的道長蛆楞。 經(jīng)常有香客問我,道長夹厌,這世上最難降的妖魔是什么豹爹? 我笑而不...
    開封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮矛纹,結(jié)果婚禮上臂聋,老公的妹妹穿的比我還像新娘。我一直安慰自己或南,他們只是感情好孩等,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著采够,像睡著了一般肄方。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蹬癌,一...
    開封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天权她,我揣著相機(jī)與錄音,去河邊找鬼逝薪。 笑死隅要,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的董济。 我是一名探鬼主播步清,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了廓啊?” 一聲冷哼從身側(cè)響起欢搜,我...
    開封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎谴轮,沒想到半個(gè)月后狂巢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡书聚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年唧领,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雌续。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡斩个,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出驯杜,到底是詐尸還是另有隱情受啥,我是刑警寧澤,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布鸽心,位于F島的核電站滚局,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏顽频。R本人自食惡果不足惜藤肢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糯景。 院中可真熱鬧嘁圈,春花似錦、人聲如沸蟀淮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怠惶。三九已至涨缚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間策治,已是汗流浹背脓魏。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留览妖,地道東北人轧拄。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像讽膏,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拄丰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

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