ReactiveCocoa學(xué)習(xí)筆記三--框架總覽(譯)

慣例廢話

學(xué)習(xí)了一段時間的RAC后, 對有些概念開始慢慢清晰, 然后再次看了這篇文檔, 發(fā)現(xiàn)的確是高屋建瓴地指出了很多基本的概念, 這篇筆記我將以翻譯為主, 注解為輔來寫, 同時會盡我所能來解釋一些名詞.

文末對這篇文檔的主要內(nèi)容做了一次簡單的概括, 嫌字多可以自己跳到最后查看

(o(╯□╰)o, 簡書貌似不支持頁面內(nèi)標(biāo)簽跳轉(zhuǎn), 關(guān)于附錄的東西,各位看官要手動拖到最下面了)

原文中的一些名詞我打算保留, 避免在描述和類名之間對應(yīng)加上一道鴻溝, 下面是一些參考釋意:

名詞 釋意
Stream
Monad 單子
Signal 信號
Subscribe(r) 訂閱(者)
Dispose 解除
Completed 完成
Subject 主題
Command 指令
Connection 連接
scheduler 調(diào)度器

框架總覽

這篇文檔包含了對ReactiveCocoa(譯注:后文簡稱RAC)框架中各個組件的簡要敘述, 以及對這些組件各自的職責(zé)和如何協(xié)同工作進(jìn)行解釋. 也就是說, 這篇文檔是學(xué)習(xí)新模塊的起點(diǎn), 從這里去找對應(yīng)的文檔來看.

例如, 關(guān)于RAC的例子和幫助文檔, 查看README或者設(shè)計指導(dǎo) (譯注: 這篇文檔也很有幫助, 值得一看)

Streams

Stream, 也就是RACStream抽象類, 是一系列對象的值.

值可能即可可用, 也可能將來可用(譯注: 例如懶加載), 但是必須按序列來取. 沒有辦法繞過計算第一個值而直接獲取后續(xù)的值.

Stream是Monads(譯注: 關(guān)于Monad我在附錄中有解釋, 看看先). 相比于其它非Monad的東西, Monad可以通過幾個簡單基本的操作來構(gòu)建復(fù)雜的操作. RACStream的實(shí)現(xiàn)類似于Haskell的Monoid和MonadZip.

RACStream本身并沒有什么用, 大多數(shù)stream都被當(dāng)做signalssequences了.

Signals

signal, 也就是RACSignal類, 是一個push驅(qū)動的stream(譯注: 所謂push驅(qū)動和pull驅(qū)動是數(shù)據(jù)源的角度來看的, 對應(yīng)為主動和被動, push是數(shù)據(jù)源會把數(shù)據(jù)主動推出去, pull則是要自己去拉取才會拿到數(shù)據(jù)).

Signals通常代表將來會被取出的數(shù)據(jù). 當(dāng)代碼執(zhí)行完畢或數(shù)據(jù)已接收, 信號的值已被發(fā)送給subscriber. 用戶必須訂閱一個signal才能訪問它的值.

signals發(fā)送給subcriber三種不同類型的事件:

  • next事件提供了一個stream的新值. RACStream的方法只操作這種事件類型. 與Cocoa的集合不同的是, 信號包含nil是允許的.
  • error事件意味著在信號結(jié)束之前有錯誤發(fā)生了. 這個事件可能包含了一個NSError對象來指示錯誤. 錯誤必須被特殊處理掉, 它們也不會包含在stream的值中.
  • completed事件意味著信號已經(jīng)成功結(jié)束, 并且沒有更多的值會被加入到stream中了. completed事件必須要被特殊處理, 它不會被stream包含.

一個信號的生命周期中包含了一系列的next事件, 最終伴隨一個error或者completed事件而結(jié)束(不會2者同時出現(xiàn)).

Subscription

一個Subscriber可以是任何東西, 它等待著信號的事件到來. 在RAC中, subscriber是任意實(shí)現(xiàn)了RACSubscriber協(xié)議的對象.

通過調(diào)用-subscribeNext:error:completed:方法或其他便利方法來創(chuàng)建一個subscription. 技術(shù)上來說, 大多數(shù)RACStream和RACSignal操作也會創(chuàng)建subscription, 通常是一些實(shí)現(xiàn)細(xì)節(jié)的中間態(tài)subscription.

Subscription會持有信號, 但是會在signal發(fā)送completed或者error事件后自動dispose.(譯注: RAC內(nèi)存管理第一條--必須保證signal以completed或error事件收尾). subscription也可以手動dispose

Subjects

subject, 也就是RACSubject類, 是一個可以手動控制的Signal.(譯注: 也就是實(shí)現(xiàn)了RACSubscription協(xié)議)

Subject可以被看作是"可變"的signal, 就像NSMutableArray之于NSArray. Subject在把非RAC代碼代入到Signal的世界中起到了非常重要的橋接作用.

例如, 可以取代在block回調(diào)中處理應(yīng)用邏輯, 這些block可以簡單地發(fā)送事件來共享subject. subject可以作為RACSignal返回, 隱藏回調(diào)的實(shí)現(xiàn)細(xì)節(jié).

一些Subject還提供了額外的操作. 比如RACReplaySubject可以用來緩存事件, 分發(fā)給以后的subscriber, 就像一個網(wǎng)絡(luò)請求已經(jīng)結(jié)束了, 但是其它處理這個結(jié)果的事情還未就緒.

(譯注: Subject相比較Signal有三個需要注意的點(diǎn), 一是Subject可以自己發(fā)送事件, 而Signal不行; 二是Subject發(fā)送的值是共享的, 無論多少subcriber收到的都是同一份, 而Signal不是; 三是Subject是熱信號(Hot Signal)而Signal是冷信號(Cold Signal). 關(guān)于冷熱信號在附錄也有簡單闡述, 看看先)

Commands

Command, 也就是RACCommand類, 創(chuàng)建和訂閱一個Signal來響應(yīng)一些操作. 這使用戶在APP上的交互當(dāng)作副作用(side-effecting)(譯注: side-effecting在學(xué)習(xí)RAC中會出現(xiàn)多次, 總體來說就是用戶對狀態(tài)的修改, 因為RAC的本意就是封裝了所有狀態(tài)的修改, 因此, 如果用戶自己在某些代碼中要自己管理某些狀態(tài), 就會導(dǎo)致和一般字面上的意義不一樣, 就是副作用的代碼, 具體可以看看學(xué)習(xí)筆記四中使副作用顯性化的描述.)來執(zhí)行變得更加容易了.

通常一個觸發(fā)指令的作用是UI驅(qū)動的, 例如一個按鈕被點(diǎn)擊了. Command也可以通過信號來自動disable掉, 并且這個disable的狀態(tài)還可以通過UI中disable相關(guān)聯(lián)的控件來體現(xiàn).

在OS X上, RAC添加了一個rac_command屬性到NSButton來自動設(shè)置這些行為.

Connections

connection, 也就是RACMulticastConnection類, 是一次多個subscriber之間共享的訂閱.

Signal默認(rèn)是cold, 意思是每一次添加了新的subscriber, 都會開始執(zhí)行任務(wù). 這個行為通常是值得的, 因為這意味著對每個subscriber來說, 數(shù)據(jù)每次都會被重新計算, 但是這樣的行為在Signal有副作用或任務(wù)龐大的時候也會出問題(例如, 發(fā)送一個網(wǎng)絡(luò)請求).

connection通過RACSignal的-publish-multicast方法來創(chuàng)建, 并且保證無論有這個connection被訂閱了多少次, 都只有一個潛在的訂閱被創(chuàng)建. 一旦連接上, connection就稱被為hot, 并且潛在的訂閱會一直保持活躍, 直到所有的的connection的訂閱都已經(jīng)dispose.

Sequences

sequences, 也就是RACSequence類, 是一個pull驅(qū)動的stream.

Sequence算是一種集合類, 類似于NSArray. 不過與數(shù)組不同的是, sequence里面的值默認(rèn)是計算的(只有當(dāng)它們被用到時才計算), 這樣提高了只有一部分sequence值被訪問的性能. 與Cocoa集合類一樣, sequence不能包含nil.

Sequence與Clojure的sequence或Haskell的List類似.

RAC添加了-rac_sequence方法到大多數(shù)Cocoa的集合類中, 從而允許它們使用RACSequence來替代之.

Disposables

RACDisposable類被用來取消操作和資源清理.

Disposables最常用來解除對Signal的訂閱. 當(dāng)訂閱被dispose, 對應(yīng)的subscriber將再也不會受到Signal發(fā)送的事件了. 除此之外, 任何與此次訂閱相關(guān)的任務(wù)(后臺處理, 網(wǎng)絡(luò)請求等)都會被取消掉, 因為這些結(jié)果已經(jīng)不再需要了.

查看RAC的設(shè)計指導(dǎo)獲取更多關(guān)于取消操作的信息.

Schedulers

scheduler, 也就是RACScheduler類, 是一系列的操作隊列來支持Signal執(zhí)行任務(wù)或分發(fā)結(jié)果.

scheduler與GCD隊列類似, 而且scheduler支持去掉操作(因為Disposables), 并且總是順序執(zhí)行. 有一個例外就是+immediateScheduler, 這個scheduler不會提供同步執(zhí)行. 這有助于防止死鎖, 并且鼓勵使用Signal操作符來取代阻塞任務(wù).

RACScheduler與NSOperationQueue也有一些類似, 但是scheduler不支持任務(wù)排序或或者說是一個任務(wù)依賴另外一個.

Value types

RAC提供了一些五花八門的類來方便stream中值的表示:

  • RACTuple是一個輕量, 常量大小的集合, 允許包含nil(會被表示為RACTupleNil). 通常被來表示多個stream值的混合.
  • RACUnit是一個表示"空值"的單例. 它用來表示stream中已經(jīng)沒有更多有意義的值了
  • RACEvent把任意的Signal事件表示為一個單一的值. 主要用于RACSignal的-materialize方法.

<a name="Conclusion"></a>總結(jié)

這篇文檔除了描述了一些名詞的概念之外, 更重要的是告訴了我們各個類之間的細(xì)微差別:

  • RACSignal是冷信號, 每次訂閱都會執(zhí)行一次任務(wù)
  • RACSubject是熱信號, 每個任務(wù)都只執(zhí)行一次, 各subscriber共享結(jié)果
  • RACReplaySubject相比RACSubject多了一個緩沖區(qū), 可以回放之前的任務(wù)
  • RACCommand主要用于UI相關(guān)的操作
  • RACDisposable可以取消對Signal的訂閱
  • RACMulticastConnection可以合并多個訂閱為一個, 避免任務(wù)被多次執(zhí)行
  • ....

附錄

<a name="Monad"></a>Monad

關(guān)于Monad在Wikipedia的解釋中有一句:

A monad is defined by a return operator that creates values, and a bind operator used to link the actions in the pipeline.

也就是說, 一個Monad被定義為返回一個構(gòu)造值的操作符, 并且一個bind操作符用來在管道中連接多個操作.

貌似還挺繞, 其實(shí)就是說, Monad本質(zhì)是一個操作符(可以理解為一個函數(shù)), 這個操作符的作用就是返回一個數(shù)值. 為什么這么麻煩, 而不直接返回這個數(shù)值呢? 后面這句話解釋了原因, 就是如果直接返回數(shù)值的話, 那就無法繼續(xù)連接操作了, 所以這邊定義了一個bind操作來專門連接多個操作符. 具體參考Linux命令行的管道.

<a name="ColdHotSignal"></a>冷熱信號

關(guān)于冷熱信號我之前在網(wǎng)上看到一位博主的博客關(guān)于冷熱信號的解釋大意如下:

Signal就像插座, subscriber就像是插頭, 如果沒有subscriber來訂閱Signal, 那就是"沒通電", 這信號就是"冷"的, 反之就是"熱"的.

然后我又看到美團(tuán)的技術(shù)博客上說的不一樣, 主要信息摘抄圖下:

1.熱信號是主動的, 即使沒有訂閱者, 也會時刻推送...而冷信號是被動的, 只有訂閱的時候才會發(fā)送信息...

2.熱信號可以有多個訂閱者,是一對多,信號可以與訂閱者共享信息...而冷信號只能一對一,當(dāng)有不同的訂閱者, 消息會重新完成發(fā)送...

兩位描述差距很大, 所以秉著追尋事實(shí)的心態(tài), 我找到了官方文檔里面有這么一句冷熱信號對比:

Is the signal hot (already activated by the time it's returned to the caller) or cold (activated when subscribed to)

上下文是在探究RACSignal所代表的含義, 從這里我們可以看出冷熱信號的一個重要區(qū)別:

熱信號: 這個信號返回給調(diào)用者的時候就已經(jīng)激活
冷信號: 當(dāng)被訂閱的時候激活

在文檔中沒有找到更多的對比解釋, 但我覺得已經(jīng)足夠描述兩者的區(qū)別了. 所以從這可以看出, 美團(tuán)技術(shù)團(tuán)隊的描述是更加準(zhǔn)確的, 當(dāng)然, 關(guān)于一對多這個說法, 我暫且保留意見, 因為這不是核心區(qū)別, 冷信號也可以有多個subscriber, 只不過值不是共享的.

這也提醒我們, 很多時候官方文檔還是準(zhǔn)確的, 很多時候我們在學(xué)習(xí)的時候, 如果可以的話, 還是盡量去看原文檔, 盡量減少理解誤差.

還值得一提的是, RAC3.0版本對冷熱信號的類使用上有一定的修改, 參考目錄

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市帽氓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宙暇,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)傻粘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來帮掉,“玉大人抹腿,你說我怎么就攤上這事⌒袷伲” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵崇败,是天一觀的道長盅称。 經(jīng)常有香客問我,道長后室,這世上最難降的妖魔是什么缩膝? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮岸霹,結(jié)果婚禮上疾层,老公的妹妹穿的比我還像新娘。我一直安慰自己贡避,他們只是感情好痛黎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布予弧。 她就那樣靜靜地躺著,像睡著了一般湖饱。 火紅的嫁衣襯著肌膚如雪掖蛤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天井厌,我揣著相機(jī)與錄音蚓庭,去河邊找鬼。 笑死仅仆,一個胖子當(dāng)著我的面吹牛器赞,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播墓拜,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼港柜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了撮弧?” 一聲冷哼從身側(cè)響起潘懊,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贿衍,沒想到半個月后授舟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贸辈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年释树,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擎淤。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡奢啥,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出嘴拢,到底是詐尸還是另有隱情桩盲,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布席吴,位于F島的核電站赌结,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏孝冒。R本人自食惡果不足惜柬姚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望庄涡。 院中可真熱鬧量承,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卦洽,卻和暖如春贞言,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阀蒂。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工该窗, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蚤霞。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓酗失,卻偏偏與公主長得像,于是被迫代替她去往敵國和親昧绣。 傳聞我的和親對象是個殘疾皇子规肴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

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