RxSwift-四種Subject的基本用法

上節(jié)末尾员舵,我們提到了Subject。既然它可以同時作為Observable和Observer徘钥,我們就直奔主題变骡,從一個叫做PublishSubject的對象開始离赫,感受下Subject的用法。

PublishSubject

顧名思義塌碌,PublishSubject就像個出版社渊胸,到處收集內(nèi)容,此時它是一個Observer台妆,然后發(fā)布給它的訂閱者翎猛,此時,它是一個Observable接剩。

首先切厘,創(chuàng)建一個PublishSubject很簡單,就像創(chuàng)建一個普通的類對象一樣:

let subject = PublishSubject<String>()

其中PublishSubject的泛型參數(shù)懊缺,表示它可以訂閱到的疫稿,以及可以發(fā)布的事件類型。

其次,當我們把subject當作Observer的時候而克,可以使用onNext方法給它發(fā)送事件:

subject.onNext("Episode1 updated")

第三靶壮,當我們把subject當作Observable的時候怔毛,訂閱它的代碼和訂閱普通的Observable完全一樣:

let sub1 = subject.subscribe(onNext: {
    print("Sub1 - what happened: \($0)")
})

但是執(zhí)行一下就會發(fā)現(xiàn)员萍,控制臺上不會顯示任何訂閱消息,也就是說sub1沒有訂閱到任何內(nèi)容拣度。這是因為PublishSubject執(zhí)行的是“會員制”碎绎,它只會把最新的消息通知給消息發(fā)生之前的訂閱者。用序列圖表示出來抗果,就是這樣的:

image

可以看到筋帖,在紅燈之前訂閱,就可以訂閱到紅冤馏、綠日麸、藍全部事件,如果在藍燈之前訂閱逮光,就只能訂閱到藍色事件了代箭。于是,為了訂閱到subject的事件涕刚,我們得把訂閱的代碼嗡综,放到通知subject前面:

let sub1 = subject.subscribe(onNext: {
    print("Sub1 - what happened: \($0)")
})

subject.onNext("Episode1 updated")

重新執(zhí)行下,就能看到Sub1 - what happened: Episode1 updated的通知了杜漠。然后极景,再來觀察下面代碼的執(zhí)行結(jié)果:

sub1.dispose()

let sub2 = subject.subscribe(onNext: {
    print("Sub2 - what happened: \($0)")
})

subject.onNext("Episode2 updated")
subject.onNext("Episode3 updated")

sub2.dispose()

  • 首先,在執(zhí)行過sub1.dispose()之后驾茴,sub1就不會再接收來自subject的任何消息了盼樟;
  • 其次,subject有了一個新的訂閱者sub2锈至;
  • 第三晨缴,subject又捕獲到了兩條新的消息。按照剛才的說法裹赴,sub2不會接收到訂閱之前的消息喜庞,因此,我們應該只能在控制臺看到Sub2 - what happened: Episode2 updatedSub2 - what happened: Episode3 updated這兩條消息棋返;
  • 最后延都,sub2取消對subject的訂閱;

重新執(zhí)行一下睛竣,就能在控制臺看到結(jié)果了晰房。

BehaviorSubject

如果你希望Subject從“會員制”變成“試用制”,就需要使用BehaviorSubject。它和PublisherSubject唯一的區(qū)別殊者,就是只要有人訂閱与境,它就會向訂閱者發(fā)送最新的一次事件作為“試用”。

image

如圖所示猖吴,BehaviorSubject帶有一個紫燈作為默認消息摔刁,當紅燈之前訂閱時,就會收到紫色及以后的所有消息海蔽。而在綠燈之后訂閱共屈,就只會收到綠燈及以后的所有消息了。因此党窜,當初始化一個BehaviorSubject對象的時候拗引,要給它指定一個默認的推送消息:

let subject = BehaviorSubject<String>(
    value: "RxSwift step by step")

然后,當我們再執(zhí)行先訂閱幌衣,后發(fā)送消息的邏輯時:

let sub1 = subject.subscribe(onNext: {
    print("Sub1 - what happened: \($0)")
})

subject.onNext("Episode1 updated")

由于BehaviorSubject有了一個默認的事件矾削,sub1訂閱之后,就會陸續(xù)收到RxSwift step by stepSub1 - what happened: Episode1 updated的消息了豁护。此時哼凯,如果我們再添加一個新的訂閱者:

let sub2 = subject.subscribe(onNext: {
    print("Sub2 - what happened: \($0)")
})

此時,sub2就只能訂閱到Sub2 - what happened: Episode1 updated消息了择镇。如果我們要讓sub2在訂閱的時候獲取到過去所有的消息挡逼,就需要使用ReplaySubject

ReplaySubject

ReplaySubject的行為和BehaviorSubject類似腻豌,都會給訂閱者發(fā)送歷史消息家坎。不同地方有兩點:

  • ReplaySubject沒有默認消息,訂閱空的ReplaySubject不會收到任何消息吝梅;
  • ReplaySubject自帶一個緩沖區(qū)虱疏,當有訂閱者訂閱的時候,它會向訂閱者發(fā)送緩沖區(qū)內(nèi)的所有消息苏携;
image

ReplaySubject緩沖區(qū)的大小做瞪,是在創(chuàng)建的時候確定的:

let subject = ReplaySubject<String>.create(bufferSize: 2)

這樣,我們就創(chuàng)建了一個可以緩存兩個消息的ReplaySubject右冻。作為Observable装蓬,它此時是一個空的事件序列,訂閱它纱扭,不會收到任何消息:

let sub1 = subject.subscribe(onNext: {
    print("Sub1 - what happened: \($0)")
})

然后牍帚,我們讓subject接收3個事件,sub1就會收到三次事件訂閱:

subject.onNext("Episode1 updated")
subject.onNext("Episode2 updated")
subject.onNext("Episode3 updated")

// Sub1 - what happened: Episode1 updated
// Sub1 - what happened: Episode2 updated
// Sub1 - what happened: Episode3 updated

這時乳蛾,我們再給subject添加一個訂閱者:

let sub2 = subject.subscribe(onNext: {
    print("Sub2 - what happened: \($0)")
})

// Sub2 - what happened: Episode2 updated
// Sub2 - what happened: Episode3 updated

由于subject緩沖區(qū)的大小是2暗赶,它會自動給sub2發(fā)送最新的兩次歷史事件鄙币。在控制臺中執(zhí)行一下,就可以看到注釋中的結(jié)果了蹂随。

Variable

除了事件序列之外十嘿,在平時的編程中我們還經(jīng)常需遇到一類場景,就是需要某個值是有“響應式”特性的岳锁,例如可以通過設置這個值來動態(tài)控制按鈕是否禁用绩衷,是否顯示某些內(nèi)容等。為了方便這個操作浸锨,RxSwift還提供了一個特殊的subject唇聘,叫做Variable版姑。

我們可以像定義一個普通變量一樣定義一個Variable

let stringVariable = Variable("Episode1")

當我們要訂閱一個Variable對象的時候柱搜,要先明確使用asObservable()方法。而不像其他subject一樣直接訂閱:

let stringVariable = Variable("Episode1")

let sub1 = stringVariable
    .asObservable()
    .subscribe {
    print("sub1: \($0)")
}

// sub1: next(Episode1)

而當我們要給一個Variable設置新值的時候剥险,要明確訪問它的value屬性聪蘸,而不是使用onNext方法:

stringVariable.value = "Episode2"

// sub1: next(Episode2)

最后要說明的一點是,Variable只用來表達一個“響應式”值的語義表制,因此健爬,它有以下兩點性質(zhì):

  • 絕不會發(fā)生.error事件;
  • 無需手動給它發(fā)送.complete事件表示完成么介;

因此娜遵,下面的代碼都會導致編譯錯誤:

// !!! The following code CANNOT compile !!!
stringVariable.asObservable().onError(MyError.myError)
stringVariable.asObservable().onCompleted()

What's next?

以上,就是RxSwift中4種Subject的用法壤短。至此设拟,我們就一切準備就緒了,接下來久脯,我們就在一個真實的App里纳胧,逐步了解如何用RxSwift實現(xiàn)一些之前常見的開發(fā)任務。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帘撰,一起剝皮案震驚了整個濱河市跑慕,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摧找,老刑警劉巖核行,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蹬耘,居然都是意外死亡芝雪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門婆赠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來绵脯,“玉大人佳励,你說我怎么就攤上這事∏欤” “怎么了赃承?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長悴侵。 經(jīng)常有香客問我瞧剖,道長,這世上最難降的妖魔是什么可免? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任抓于,我火速辦了婚禮,結(jié)果婚禮上浇借,老公的妹妹穿的比我還像新娘捉撮。我一直安慰自己,他們只是感情好妇垢,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布巾遭。 她就那樣靜靜地躺著,像睡著了一般闯估。 火紅的嫁衣襯著肌膚如雪灼舍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天涨薪,我揣著相機與錄音骑素,去河邊找鬼。 笑死刚夺,一個胖子當著我的面吹牛献丑,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播光督,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼阳距,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了结借?” 一聲冷哼從身側(cè)響起筐摘,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎船老,沒想到半個月后咖熟,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡柳畔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年馍管,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片薪韩。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡确沸,死狀恐怖捌锭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情罗捎,我是刑警寧澤观谦,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站桨菜,受9級特大地震影響豁状,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜倒得,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一泻红、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧霞掺,春花似錦谊路、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至挤巡,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間酷麦,已是汗流浹背矿卑。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留沃饶,地道東北人母廷。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像糊肤,于是被迫代替她去往敵國和親琴昆。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

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