ReactiveCocoa

目錄

一、ReactiveCocoa結(jié)合了多種編程風(fēng)格

二、在MVVM的項目中,為何總是會提到RAC呢?

三、ReactiveCocoa一些概念和用法


之前使用ReactiveCocoa+MVVM做過一次項目,當(dāng)時使用它的原因就是感覺一個是新,一個是非常的簡潔,看起來很酷。

當(dāng)時別人問我ReactiveCocoa是什么,我都會回答:函數(shù)響應(yīng)式編程。當(dāng)時也不懂什么意思,那么現(xiàn)在再來回顧一下ReactiveCocoa。

一、ReactiveCocoa結(jié)合了多種編程風(fēng)格:

函數(shù)式編程(Functional Programming)

函數(shù)式編程思想:是把操作盡量寫成一系列嵌套的函數(shù)或者方法調(diào)用。

響應(yīng)式編程(Reactive Programming)

響應(yīng)式編程思想:不需要考慮調(diào)用順序,只需要知道考慮結(jié)果,類似于蝴蝶效應(yīng),產(chǎn)生一個事件,會影響很多東西,這些事件像流一樣的傳播出去,然后影響結(jié)果。

那么我們簡單舉個例子:

RACSignal *signalA = RACObserve(self, a);

RACSignal *signalB = RACObserve(self, b);

RAC(self.label, text) = [RACSignal combineLatest:@[signalA,signalB] reduce:^(NSInteger countA, NSInteger countB){

return [NSString stringWithFormat:@"結(jié)果:%ld",countA+countB];

}];


那看看我們通常的做法

- (void)sumAction

{

self.label.text = [NSString stringWithFormat:@"結(jié)果:%ld",self.a+self.b];

}

看起來這個操作放在了一個方法中,挺簡單的,可是每次調(diào)用self.a = X;或者self.b = Y;時,想要顯示正確的值,那么必定要再調(diào)用一次[self sumAction];

當(dāng)我們執(zhí)行順序為self.a = X; [self sumAction]; self.b = Y; 這個時候沒有得到我們想要的X+Y的值,這不是響應(yīng)式的。

如果我們將[self sumAction];的調(diào)用放在set方法中呢?那么確實是響應(yīng)式的了,但用到了至少兩個方法。

在MVVM的項目中,為何總是會提到RAC呢?

MVVM從MVC演化而來,為的是減少C的邏輯和業(yè)務(wù)。如果沒有RAC,那么我們得使用NSNotification、delegate、KVO等將V變化產(chǎn)生的數(shù)據(jù)傳給VM,從而改變M的值。NSNotification可能跨度大點,尤其delegate和KVO會免不了將業(yè)務(wù)再次放到C中,如果不放到C中,那么這個VM就會與這個View綁定得比較緊,而ViewModel有可能并不是只服務(wù)于特定的一個View,這樣的話使用更加松散的綁定關(guān)系能夠降低ViewModel和View之間的耦合度。

因此View一旦產(chǎn)生數(shù)據(jù)了扔信號扔給ViewModel,使用ReactiveCocoa更能體現(xiàn)其精髓。

注:大部分MVVM架構(gòu)都會使用ReactiveCocoa,但是使用ReactiveCocoa的iOS應(yīng)用不一定就是基于MVVM架構(gòu)的。MVVM的關(guān)鍵是要有View Model。


三、ReactiveCocoa一些概念和用法:

1.map:

map是將一張表中的值映射新值到另一張表中

NSArray*mappedArray=[array rx_mapWithBlock:^id(ideach){

return @(pow([each integerValue], 2));

}];

注:這是建立了一個新的數(shù)組,而不是將原數(shù)組的值進(jìn)行改變

這所對應(yīng)的是

NSMutableArray*mutableArray=[NSMutableArrayarrayWithCapacity:array.count];

for(NSNumber*numberinarray){[mutableArrayaddObject:@(pow([number integerValue], 2))];

}

NSArray*mappedArray=[NSArrayarrayWithArray:mutableArray];

這就是更高級別的函數(shù)更占優(yōu)勢的地方

2.filter(過濾)

3.fold(結(jié)合)

//合數(shù)值

NSNumber*sum=[array rx_foldWithBlock:^id(id?memo,id?each){

return @([memo integerValue] + ?[eachintegerValue]);

}];

//拼字符串

[[array rx_mapWithBlock:^id(id?each){

return [each stringValue];

}] rx_foldInitialValue:@""block:^id(id?memo,id?each){

return [memo stringByAppendingString:each];

}];

4.Streams and Sequences

一系列的值抽象的被稱為流,你可以認(rèn)為流就像一個管道,其中值從一端進(jìn)入從另一端放出。除非在管道的尾端當(dāng)值出來時你能訪問,訪問過去的值甚至是當(dāng)前值都是不可能的。沒關(guān)系,我們拭目以待。

一系列的值,是嗎?有點像一個列表,或在我們的例子中,一個數(shù)組。事實上,我們可以使用rac_sequence方法很容易地將一個NSArray轉(zhuǎn)化成流。

NSArray*array=@[@(1),@(2),@(3)];

RACSequence*stream=[array rac_sequence];//將數(shù)組轉(zhuǎn)化成流

[stream map:^id(id value){

return @(pow([value integerValue],2));

}];

NSLog(@"%@",[stream array]);//將流又轉(zhuǎn)化成數(shù)組

//原來項目中使用了這個方法是這樣的一個過程,map可以將字典轉(zhuǎn)化成對象,然后就成為了對象的數(shù)組

NSLog(@"%@",[[[array rac_sequence] map:^id(idvalue){

return @(pow([value integerValue],2));

}] array]);

ReactiveCocoa包含left fold和right fold。left

fold是從開始往結(jié)尾穿過一個數(shù)組,right fold是反的

5.Signals

信號是另一種類型的流,對比sequences(序列),信號是推驅(qū)動,新值通過管道推壓并且不能拉出,在以后他們把將被遞送的數(shù)據(jù)抽取出來。

信號包括三種不同的類型值:Next、Error、Completion.

值得注意的是,Error和Completion只能通過信號送出一次,并且只有一個被送出。

6.Subscriptions

[self.textField.rac_textSignal subscribeNext:^(id?x){

NSLog(@"New value:%@", x);

}error:^(NSError*error){

NSLog(@"Error: %@",error);

}completed:^{

NSLog(@"Completed.");

}];

在textfield中輸入字符時,發(fā)現(xiàn)信號不發(fā)送error值和當(dāng)信號deallocated的時候發(fā)送completion值,因此我們可以

[self.textField.rac_textSignal subscribeNext:^(idx){

NSLog(@"New value: %@", x);

}];

當(dāng)subscribe(訂閱)一個信號,將自動創(chuàng)建一個subscription對象,這個對象將自動保留,同時也保留了這個信號的subscribing狀態(tài),你可以手動處理訂閱者,但這不是典型的操作,一般在使用重用視圖的時候處理信號

7.Deriving State

宏RAC()有兩個參數(shù):一個對象和該對象的鍵值路徑。然后,它執(zhí)行一個單向的綁定右邊的值到鍵值路徑。值必須是對象,這就是為什么我們把布爾值包裝成一個NSNumber。

RACSignal?*validEmailSignal=[self.textField.rac_textSignalmap:^id(NSString?*value){

return @([value rangeOfString:@"@"].location!= NSNotFound);

}];

RAC(self.button,enabled)=validEmailSignal;

RAC(self.textField,textColor)=[validEmailSignalmap:^id(id?value){

if ([value boolValue]) {? ?? ? ? ? return [UIColor greenColor];

} else {

return [UIColor redColor];

}

}];

8.Commands

當(dāng)你想要發(fā)送一個信號的值對用戶交互事件響應(yīng),Commands是有用的。command的信號能被訂閱來稍后接收返回的輸出信號。

self.button.rac_command=?[[RACCommand alloc]initWithEnabled:validEmailSignal

signalBlock:^RACSignal *(idinput){

NSLog(@"Button was pressed.");

return [RACSignal empty];

}];

這個按鈕將保持disabled直到信號返回complete值(也可以是空值([RACSignal empty]))

9.RACSubject

信號提供者,自己可以充當(dāng)信號,又能發(fā)送信號。

創(chuàng)建方法:

(1)創(chuàng)建RACSubject

(2)訂閱信號

(3)發(fā)送信號

工作流程:

(1)訂閱信號時,內(nèi)部保存了訂閱者,和訂閱者響應(yīng)block

(2)當(dāng)發(fā)送信號的,遍歷訂閱者,調(diào)用訂閱者的nextBlock

注:如果訂閱信號,必須在發(fā)送信號之前訂閱信號,不然收不到信號,這也有別于RACReplaySubject

-(void)racSubjectTest

{

RACSubject *subject= [RACSubjectsubject];

[subject subscribeNext:^(idx) {

NSLog(@"1

%@,type:%@",x,NSStringFromClass(object_getClass(x)));

}];

[subject subscribeNext:^(idx) {

NSLog(@"2

%@,type:%@",x,NSStringFromClass(object_getClass(x)));

}];

[subjectsendNext:@1];

[subject subscribeNext:^(idx) {

NSLog(@"3

%@,type:%@",x,NSStringFromClass(object_getClass(x)));

}];

}

10.Hot and Cold Signals

信號通常是懶惰的,意味著它們只有在有人已經(jīng)訂閱它們的時候,它們才會工作和發(fā)送信號。每增加一個訂閱,工作就會重新執(zhí)行。對于繁瑣的操作,這是可以接受的,并且實際上這是所希望的。在ReactiveCocoa術(shù)語中,這種類型的信號被稱為“冷信號”。

有時,我們想工作立即被執(zhí)行,這種類型的信號被稱為“熱信號”。熱信號非常罕見被使用到。

11.Multicasting

Multicasting是指某個信號訂閱被共享于大量訂閱者的術(shù)語。信號,一般是“冷信號”,它有時是不可取的,執(zhí)行工作每次它都是訂閱的“冷信號”,這常常是當(dāng)副作用或工作時訂閱是昂貴的時候執(zhí)行,否則只有在適當(dāng)?shù)臅r候才會執(zhí)行。網(wǎng)絡(luò)請求浮現(xiàn)在腦海中。

于是我們創(chuàng)建來源于信號的RACMulticastConnection。你可以在RACSignal中使用publish方法或multicast:方法。前一種方法為您創(chuàng)建一個multicast的連接。后一種方法也做了同樣的事,但還采用RACSubject參數(shù)。這個subject是手動從底層信號發(fā)送值,每當(dāng)它被調(diào)用。然后,任何由底層信號發(fā)送的值有興趣訂閱連接的信號,相反(如果你提供一個subject,信號正好是這個subject)。

由于在默認(rèn)情況下信號是“冷信號”,每添加一個訂閱者,則它的工作被執(zhí)行。如果是這樣的話,那是不可取的,我們使用multicast的連接。

multicast的連接訂閱的信號,當(dāng)它已經(jīng)通過了新的值,發(fā)送這些值到信號(這作為一個公共屬性公開)。你可以多次訂閱這個信號,并且在訂閱時執(zhí)行的工作,只是一次

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容