1.Reactive Cocoa解決了什么問(wèn)題
- 傳統(tǒng)iOS開(kāi)發(fā)過(guò)程中豫喧,狀態(tài)以及狀態(tài)之間依賴過(guò)多的問(wèn)題
- 傳統(tǒng)MVC架構(gòu)的問(wèn)題:Controller比較復(fù)雜埋涧,可測(cè)試性差
- 提供統(tǒng)一的消息傳遞機(jī)制
2.基本概念
一個(gè)很好的比喻:
可以把信號(hào)想象成水龍頭当犯,只不過(guò)里面不是水积糯,而是玻璃球(value)烧颖,直徑跟水管的內(nèi)徑一樣近迁,這樣就能保證玻璃球是依次排列明肮,不會(huì)出現(xiàn)并排的情況(數(shù)據(jù)都是線性處理的菱农,不會(huì)出現(xiàn)并發(fā)情況)。水龍頭的開(kāi)關(guān)默認(rèn)是關(guān)的柿估,除非有了接收方(subscriber)循未,才會(huì)打開(kāi)。這樣只要有新的玻璃球進(jìn)來(lái)官份,就會(huì)自動(dòng)傳送給接收方只厘。可以在水龍頭上加一個(gè)過(guò)濾嘴(filter)舅巷,不符合的不讓通過(guò)羔味,也可以加一個(gè)改動(dòng)裝置,把球改變成符合自己的需求(map)钠右。也可以把多個(gè)水龍頭合并成一個(gè)新的水龍頭(combineLatest:reduce:)赋元,這樣只要其中的一個(gè)水龍頭有玻璃球出來(lái),這個(gè)新合并的水龍頭就會(huì)得到這個(gè)球飒房。
信號(hào)(Signal):信號(hào)就是流搁凸,RAC中所有的信號(hào)都是RACStream的子類。信號(hào)有冷熱之分狠毯,信號(hào)也有中繼护糖、改變等操作。信號(hào)是讓訂閱者去訂閱嚼松,然后觸發(fā)對(duì)應(yīng)事件嫡良。
- 冷信號(hào)(Cold):是被動(dòng)的信號(hào)锰扶,只有當(dāng)你訂閱的時(shí)候,它才會(huì)發(fā)布消息寝受。只能一對(duì)一坷牛,當(dāng)有不同的訂閱者,消息會(huì)從新完整發(fā)送很澄。
- 熱信號(hào)(Hot):是主動(dòng)的信號(hào)京闰,即使你沒(méi)有訂閱事件,它仍然會(huì)時(shí)刻推送甩苛□彘梗可以有多個(gè)訂閱者,是一對(duì)多浪藻,信號(hào)可以與訂閱者共享信息捐迫。
訂閱者(Subscriber):負(fù)責(zé)接收信號(hào)執(zhí)行操作,都必須實(shí)現(xiàn)RACSubscriber協(xié)議爱葵。訂閱者之間的關(guān)系原則上是平等的施戴,但實(shí)際操作上也是有先后順序,而且還有副作用的情況需要考慮萌丈。
事件類型:信號(hào)(RACSignal)發(fā)送給訂閱者(Subscriber)的事件類型有三種赞哗,分別是next、error辆雾、completed肪笋。一個(gè)signal在因error終止或者完成前,可以發(fā)送任意數(shù)量的next事件度迂。三種事件對(duì)應(yīng)函數(shù)如下:
subscribeNext:^(id x)
subscribeError:^(NSError *error)
subscribeCompleted:^
有些地方需要注意下藤乙,比如把signal作為local變量時(shí),如果沒(méi)有被subscribe惭墓,那么方法執(zhí)行完后坛梁,該變量會(huì)被dealloc。但如果signal有被subscribe腊凶,那么subscriber會(huì)持有該signal划咐,直到signal sendCompleted或sendError時(shí),才會(huì)解除持有關(guān)系钧萍,signal才會(huì)被dealloc褐缠。
副作用(Side Effect):在每一次訂閱的是時(shí)候都會(huì)觸發(fā)對(duì)應(yīng)的操作,導(dǎo)致訂閱者收到信號(hào)的時(shí)候风瘦,結(jié)果會(huì)和其他訂閱者不同队魏。添加附加操作,如doNext:因?yàn)樗歉郊硬僮魍蛏Γ⒉桓淖兪录旧怼?/p>
生命周期:一個(gè)信號(hào)的生命周期是由任意個(gè) next 事件和一個(gè) error 事件或一個(gè) completed事件組成的胡桨。
Reactive結(jié)構(gòu)圖:
3. RACStream
RACStream結(jié)構(gòu)圖:
RACStream 是一個(gè)抽象類俐载,通常情況下,我們并不會(huì)去實(shí)例化它登失,而是直接使用它的兩個(gè)子類 RACSignal 和 RACSequence 。
RACSignal
RACSignal 并非只有一個(gè)類挖炬,事實(shí)上揽浙,它的一系列功能是通過(guò)類簇來(lái)實(shí)現(xiàn)的。
- RACEmptySignal :空信號(hào)意敛,用來(lái)實(shí)現(xiàn) RACSignal 的 +empty 方法馅巷;
- RACReturnSignal :一元信號(hào),用來(lái)實(shí)現(xiàn) RACSignal 的 +return: 方法草姻;
- RACDynamicSignal :動(dòng)態(tài)信號(hào)钓猬,使用一個(gè) block 來(lái)實(shí)現(xiàn)訂閱行為,我們?cè)谑褂?RACSignal 的 +createSignal: 方法時(shí)創(chuàng)建的就是該類的實(shí)例撩独;
- RACErrorSignal :錯(cuò)誤信號(hào)敞曹,用來(lái)實(shí)現(xiàn) RACSignal 的 +error: 方法;
- RACChannelTerminal :通道終端综膀,代表 RACChannel 的一個(gè)終端澳迫,用來(lái)實(shí)現(xiàn)雙向綁定。
對(duì)于 RACSignal 類簇來(lái)說(shuō)剧劝,最核心的方法莫過(guò)于 -subscribe: 了橄登,這個(gè)方法封裝了訂閱者對(duì)信號(hào)源的一次訂閱過(guò)程,它是<font color = red>訂閱者與信號(hào)源產(chǎn)生聯(lián)系的唯一入口</font>讥此。
RACSequence
代表的是一個(gè)不可變的值的序列拢锹,從嚴(yán)格意義上講,RACSequence 并不能算作是信號(hào)源萄喳,因?yàn)樗⒉荒芟?RACSignal 那樣卒稳,可以被訂閱者訂閱,但是它與 RACSignal 之間可以非常方便地進(jìn)行轉(zhuǎn)換取胎。RACSequence 存在的最大意義就是為了簡(jiǎn)化 Objective-C 中的集合操作展哭。
從理論上說(shuō),一個(gè) RACSequence 由兩部分組成:
- head :指的是序列中的第一個(gè)對(duì)象闻蛀,如果序列為空匪傍,則為 nil ;
- tail :指的是序列中除第一個(gè)對(duì)象外的其它所有對(duì)象觉痛,同樣的役衡,如果序列為空,則為 nil 薪棒。
RACSequence 的一系列功能也是通過(guò)類簇來(lái)實(shí)現(xiàn)的手蝎,它共有九個(gè)用來(lái)實(shí)現(xiàn)不同功能的私有子類:
- RACUnarySequence :一元序列榕莺,用來(lái)實(shí)現(xiàn) RACSequence 的 +return: 方法;
- RACIndexSetSequence :用來(lái)遍歷索引集棵介;
- RACEmptySequence :空序列钉鸯,用來(lái)實(shí)現(xiàn) RACSequence 的 +empty 方法;
- RACDynamicSequence :動(dòng)態(tài)序列邮辽,使用 blocks 來(lái)動(dòng)態(tài)地實(shí)現(xiàn)一個(gè)序列唠雕;
- RACSignalSequence :用來(lái)遍歷信號(hào)中的值;
- RACArraySequence :用來(lái)遍歷數(shù)組中的元素吨述;
- RACEagerSequence :非懶計(jì)算的序列岩睁,在初始化時(shí)立即計(jì)算所有的值;
- RACStringSequence :用來(lái)遍歷字符串中的字符揣云;
- RACTupleSequence :用來(lái)遍歷元組中的元素捕儒。
4.RACCommand
RACCommand:代表著與交互后即將執(zhí)行的一段流程。通常這個(gè)交互是UI層級(jí)的邓夕,比如你點(diǎn)擊個(gè)Button刘莹。RACCommand可以方便的將Button與enable狀態(tài)進(jìn)行綁定,也就是當(dāng)enable為NO的時(shí)候翎迁,這個(gè)RACCommand將不會(huì)執(zhí)行栋猖。RACCommand還有一個(gè)常見(jiàn)的策略:allowsConcurrentExecution,默認(rèn)為NO汪榔,也就是是當(dāng)你這個(gè)command正在執(zhí)行的話蒲拉,你多次點(diǎn)擊Button是沒(méi)有用的。創(chuàng)建一個(gè)RACCommand的返回值是一個(gè)Signal痴腌,這個(gè)Signal會(huì)返回next或者complete或者error雌团。它有幾個(gè)比較重要的屬性:executionSignals / errors / executing。
- executionSignals是signal of signals士聪,如果直接subscribe的話會(huì)得到一個(gè)signal锦援,而不是我們想要的value,所以一般會(huì)配合switchToLatest剥悟。
- errors灵寺。跟正常的signal不一樣,RACCommand的錯(cuò)誤不是通過(guò)sendError來(lái)實(shí)現(xiàn)的区岗,而是通過(guò)errors屬性傳遞出來(lái)的略板。
- executing表示該command當(dāng)前是否正在執(zhí)行。
5.Reactive Cocoa的使用
combineLatest(聚合信號(hào)):把不同信號(hào)產(chǎn)生的最新的值聚合在一起慈缔,并生成一個(gè)新的信號(hào)叮称。每次這兩個(gè)源信號(hào)的任何一個(gè)產(chǎn)生新值時(shí),reduce block都會(huì)執(zhí)行,block的返回值會(huì)發(fā)給下一個(gè)信號(hào)瓤檐。
Map(轉(zhuǎn)換):Map是接收到信號(hào)后赂韵,對(duì)信號(hào)的返回值處理,然后根據(jù)需要改變信號(hào)的返回值挠蛉,繼續(xù)傳遞該信號(hào)祭示。
Injecting effects(注入效果):對(duì)信號(hào)做一些處理 -doNext: -doError: -doCompleted:。
Filtering(過(guò)濾):過(guò)濾不符合需求的信號(hào)谴古。
FlattenMap(平鋪拓?fù)洌?/strong>:收到信號(hào)后绍移,對(duì)信號(hào)返回值進(jìn)行處理后,返回一個(gè)新的信號(hào)讥电,可以改變信號(hào)的返回值。
Flatten(平鋪):當(dāng)訂閱者的數(shù)量達(dá)到最大當(dāng)前訂閱數(shù)的時(shí)候轧抗,合并接收者發(fā)送的各種信號(hào)到一個(gè)平鋪信號(hào)中恩敌。新的信號(hào)會(huì)像其他信號(hào)一樣被排隊(duì)、訂閱横媚。
Concat(拼接):一個(gè)信號(hào)拼接到另一個(gè)信號(hào)后面
····
6.RACSignal (Debugging)
/// Logs all events that the receiver sends.
- (RACSignal *)logAll;
/// Logs each `next` that the receiver sends.
- (RACSignal *)logNext;
/// Logs any error that the receiver sends.
- (RACSignal *)logError;
/// Logs any `completed` event that the receiver sends.
- (RACSignal *)logCompleted;
調(diào)試輔助函數(shù)纠炮,可以觀察信號(hào)的關(guān)閉傳遞等。
附:
函數(shù)式編程(Functional Programming):使用高階函數(shù)灯蝴,例如函數(shù)用其他函數(shù)作為參數(shù)恢口。
響應(yīng)式編程(Reactive Programming):關(guān)注于數(shù)據(jù)流和變化傳播。響應(yīng)式編程可以避免使用追蹤瞬時(shí)狀態(tài)的的實(shí)例變量穷躁。
RAC()宏:等價(jià)于產(chǎn)生信號(hào)耕肩、傳遞信號(hào),以及訂閱信號(hào)问潭。針對(duì)某個(gè)對(duì)象的一個(gè)屬性進(jìn)行綁定猿诸,信號(hào)返回值是對(duì)屬性的賦值
。
取消信號(hào):在一個(gè)completed或者error事件之后狡忙,訂閱會(huì)自動(dòng)移除梳虽;也可以通過(guò)RACDisposable 手動(dòng)移除訂閱。
雙向綁定:兩邊任何一邊變化灾茁,都會(huì)對(duì)另一邊產(chǎn)生影響窜觉。eg. RACChannelTo(self, blockShowText) = RACChannelTo(self.viewModel, blockShowText);
FlattenMap和Map的區(qū)別:Map是通過(guò)FlattenMap來(lái)實(shí)現(xiàn)的,Map只是改變分發(fā)的值北专。而FlattenMap不僅可以獲得上一個(gè)信號(hào)的值禀挫,還能激活下一個(gè)信號(hào),形成這種鏈?zhǔn)椒磻?yīng)逗余。Map是FlattenMap在流中信號(hào)數(shù)量為1特咆,而且信號(hào)值是block的返回值的特殊情況。Map是改變一個(gè)信號(hào)的返回值,F(xiàn)lattenMap是創(chuàng)建一個(gè)新的信號(hào)腻格。
MVVM概述: