RxSwift(六) - Subjects、 Variables

Subjects

創(chuàng)建 Observable 序列之后, 要預(yù)先將要發(fā)出的數(shù)據(jù)準(zhǔn)備好, 等到有人訂閱時(shí), 再將數(shù)據(jù)通過 Event 發(fā)出去.

我們希望 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è)就可以使用 Subjects 來實(shí)現(xiàn).

Subjects 基本介紹

(1) Subjects 它是訂閱者, 也是 Obervable :

  • 它是訂閱者, 因?yàn)樗軌騽?dòng)態(tài)的接收新的值
  • 它是一個(gè) Observable, 是因?yàn)楫?dāng) Subjects 有了新的值之后, 就會(huì)通過 Event 將新值發(fā)出給他的所有訂閱者.

(2) 一共有四種 Subjects, 分別是 PublishSubjectBehaviorSubject邪驮、ReplaySubject 坠陈、 Variable(已廢棄)BehaviorRelay(Variable替代品).

  • 它們都是 Observable, 它們的訂閱者都能收到它們發(fā)出的 Event
  • 直到 Subject 發(fā)出 .complete 或者 .errorEvent 之后, 該 Subject 才會(huì)終結(jié), 不再發(fā)出 .next 事件.
  • 對(duì)于那些在 Subject 終結(jié)后再訂閱的訂閱者, 也能收到一條 .complete 或者 .errorEvent, 告訴這個(gè)新訂閱者, 該 Subject 已經(jīng)終結(jié)
  • 它們的區(qū)別在于 : 當(dāng)一個(gè)新的訂閱者剛訂閱它的時(shí)候,能不能收到 Subject 以前發(fā)出的舊 Event, 如果能,又可以收到多少個(gè) Event.

(3) Subject 的常用方法

  • onNext() : on(.next):的簡寫, 該方法相當(dāng)于 subject 接收到一個(gè) .next 事件.
  • onError() : on(.error): 的簡寫, 該方法相當(dāng)于 subject 接收到一個(gè) .error 事件.
  • onCompleted() : on(.completed): 的簡寫, 該方法相當(dāng)于 subjet 接收到一個(gè) .completed 事件
PublishSubject

(1) 基本介紹

  • PublishSubject 是最普通的 Subjet, 它不需要初始值就能創(chuàng)建.
  • PublishSubject 的訂閱者從開始訂閱的時(shí)間點(diǎn)起,可以收到訂閱 Subject 發(fā)出的新的 Event, 而不會(huì)收到他們?cè)谟嗛喦耙寻l(fā)出的 Event.
PublishSubject.png

(2)案例

override func viewDidLoad() {
        super.viewDidLoad()
        let disposeBag = DisposeBag()
        //創(chuàng)建一個(gè)PublishSubject
        let subject = PublishSubject<String>()
        subject.onNext("11") //此時(shí)沒有訂閱者,不會(huì)輸出
        
        //首次訂閱
        subject.subscribe(onNext: { str in
            print("第一次訂閱: ", str)
        }, onCompleted: {
            print("第一次訂閱 : onCompleted")
        }).disposed(by: disposeBag)
        //有訂閱者,會(huì)輸出
        subject.onNext("22")
        
        subject.subscribe(onNext: { (str) in
            print("第二次訂閱: ", str)
        }, onCompleted: {
            print("第二次訂閱 : onCompleted")
        }).disposed(by: disposeBag)
        subject.onNext("33")//兩個(gè)訂閱者,輸出兩遍
        subject.onCompleted()//結(jié)束兩個(gè)訂閱者,打印兩遍
        subject.onNext("44")//再次發(fā)送event,不會(huì)打印
        //再有新的訂閱者,會(huì)收到onCompleted消息,通知新的訂閱者,該Subject已經(jīng)終結(jié)
        subject.subscribe(onNext: { (str) in
            print("第三次訂閱: ", str)
        }, onCompleted: {
            print("第三次訂閱 : onCompleted")
        }).disposed(by: disposeBag)
}

//輸出結(jié)果 
第一次訂閱:  22
第一次訂閱:  33
第二次訂閱:  33
第一次訂閱 : onCompleted
第二次訂閱 : onCompleted
第三次訂閱 : onCompleted
BehaviorSubject

(1) 基本介紹

  • BehaviorSubject 需要通過一個(gè)默認(rèn)初始值來創(chuàng)建
  • 當(dāng)一個(gè)訂閱者來訂閱它的時(shí)候, 這個(gè)訂閱者會(huì)立即收到 BehaviorSubject 上一個(gè)發(fā)出的 event, 之后就是正常流程
    BehaviorSubject.png

(2) 使用示例

override func viewDidLoad() {
        super.viewDidLoad()
        let disposeBag = DisposeBag()
        let subject = BehaviorSubject(value: "111")
        //第一次訂閱subject(先發(fā)出上一個(gè)event)
        subject.subscribe { (event) in
            print("第一次訂閱: ", event)
        }.disposed(by: disposeBag)
        //發(fā)送next事件
        subject.onNext("222")
        subject.onError(NSError(domain: "local", code: 0, userInfo: nil))
        //重復(fù)結(jié)束event,輸出error
        subject.subscribe { (event) in
            print("第二次訂閱: ",event)
        }.disposed(by: disposeBag)
    }
    
//輸出結(jié)果
第一次訂閱:  next(111)
第一次訂閱:  next(222)
第一次訂閱:  error(Error Domain=local Code=0 "(null)")
第二次訂閱:  error(Error Domain=local Code=0 "(null)")
ReplaySubject

(1) 基本介紹

  • ReplaySubject 在創(chuàng)建的時(shí)候需要設(shè)置一個(gè) bufferSize, 表示它發(fā)送過的 event 緩存?zhèn)€數(shù). 比如 : 一個(gè) ReplaySubjectbufferSize 設(shè)置為 2, 它發(fā)出了三個(gè) .nextevent, 那么這個(gè) subscriber 就會(huì)立即收到前面緩存的兩個(gè) .nextevent

(2) 時(shí)序圖

  • ReplaySubjectbufferSize2
  • 下面兩條訂閱, 訂閱時(shí)間點(diǎn)不同. ReplaySubject 的訂閱者一開始就能受到 ReplaySubject 之前發(fā)出的兩個(gè) Event(如果有的話).
    ReplaySubject.png

    (3)案例
override func viewDidLoad() {
        super.viewDidLoad()
        let disposeBag = DisposeBag()
        let subject = ReplaySubject<String>.create(bufferSize: 2);
        //連續(xù)發(fā)出三個(gè)event
        subject.onNext("1")
        subject.onNext("2")
        subject.onNext("3")
        //第一次訂閱
        subject.subscribe { (event) in
            print("第一次訂閱", event)
        }.disposed(by: disposeBag)
        
        subject.onNext("4")
        subject.subscribe { (event) in
            print("第二次訂閱", event)
        }
        
        subject.onCompleted();
        subject.subscribe { (event) in
            print("第三次訂閱", event)
        }.disposed(by: disposeBag)
        
    }
    
//輸出結(jié)果
第一次訂閱 next(2)
第一次訂閱 next(3)
第一次訂閱 next(4)
第二次訂閱 next(3)
第二次訂閱 next(4)
第一次訂閱 completed
第二次訂閱 completed
第三次訂閱 next(3)
第三次訂閱 next(4)
第三次訂閱 completed
BehaviorRelay

(1) 基本介紹

  • BehaviorRelay 是作為 Variable 的替代者出現(xiàn)的. 它的本質(zhì)其實(shí)也是對(duì) BehaviorRelay 的封裝, 所以它也必須要通過一個(gè)默認(rèn)的初始值進(jìn)行創(chuàng)建
  • BehaviorReplay 具有 BehaviorSubject 的功能, 能夠向它的訂閱者發(fā)出上一個(gè) event 以及之后新創(chuàng)建的 event
  • BehaviorSubject 不同的是滥酥,不需要也不能手動(dòng)給 BehaviorReply 發(fā)送 completed 或者 error 事件來結(jié)束它(BehaviorRelay 會(huì)在銷毀時(shí)自動(dòng)發(fā)送 .complete 的 event)石景。
  • BehaviorReplay 有一個(gè) value 屬性, 我們通過這個(gè)屬性可以獲取最新值. 而通過它的 accept() 方法可以對(duì)值進(jìn)行修改.

(2) 案例

override func viewDidLoad() {
        super.viewDidLoad()
        let disposeBag = DisposeBag()
        let subject = BehaviorRelay<String>(value: "111");
        // 修改value值
        subject.accept("222");
        //第一次訂閱
        subject.subscribe { (event) in
            print("第一次訂閱: ", event)
        }.disposed(by: disposeBag)
        
        //修改value值
        subject.accept("333")
        subject.subscribe { (event) in
            print("第二次訂閱 :", event)
        }.disposed(by: disposeBag)

        subject.accept("444")
    }
//輸出結(jié)果
第一次訂閱:  next(222)
第一次訂閱:  next(333)
第二次訂閱 : next(333)
第一次訂閱:  next(444)
第二次訂閱 : next(444)
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拙吉,隨后出現(xiàn)的幾起案子潮孽,更是在濱河造成了極大的恐慌,老刑警劉巖筷黔,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件往史,死亡現(xiàn)場離奇詭異,居然都是意外死亡佛舱,警方通過查閱死者的電腦和手機(jī)椎例,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門挨决,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人订歪,你說我怎么就攤上這事脖祈。” “怎么了刷晋?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵盖高,是天一觀的道長。 經(jīng)常有香客問我眼虱,道長喻奥,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任捏悬,我火速辦了婚禮撞蚕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘过牙。我一直安慰自己甥厦,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布抒和。 她就那樣靜靜地躺著矫渔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪摧莽。 梳的紋絲不亂的頭發(fā)上庙洼,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音镊辕,去河邊找鬼油够。 笑死,一個(gè)胖子當(dāng)著我的面吹牛征懈,可吹牛的內(nèi)容都是我干的石咬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼卖哎,長吁一口氣:“原來是場噩夢啊……” “哼鬼悠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起亏娜,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤焕窝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后维贺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體它掂,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年溯泣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虐秋。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榕茧。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖客给,靈堂內(nèi)的尸體忽然破棺而出用押,到底是詐尸還是另有隱情,我是刑警寧澤起愈,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布只恨,位于F島的核電站,受9級(jí)特大地震影響抬虽,放射性物質(zhì)發(fā)生泄漏官觅。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一阐污、第九天 我趴在偏房一處隱蔽的房頂上張望休涤。 院中可真熱鬧,春花似錦笛辟、人聲如沸功氨。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捷凄。三九已至,卻和暖如春围来,著一層夾襖步出監(jiān)牢的瞬間跺涤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來泰國打工监透, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留桶错,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓胀蛮,卻偏偏與公主長得像院刁,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子粪狼,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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