IOS響應式編程框架ReactiveCocoa(RAC)使用示例

ReactiveCocoa是響應式編程(FRP)在iOS中的一個實現框架,它的開源地址爲:https://github.com/ReactiveCocoa/ReactiveCocoa# ;在網上看了幾篇文章,感覺理論講了很多,但是代碼還是看不太懂,於是自己把它github文檔上的一些使用的經典示例實現了一下,項目中有需要時可以直接搬過去用,用的熟練了再讀源碼也比較容易理解。


    例1. 監聽對象的成員變量變化,當成員變量值被改變時,觸發做一些事情。

    這種情況其實就是IOS KVO機制使用的場景,使用KVO實現,通常有三個步驟:1,給對象的成員變量添加監聽;2,實現監聽回調;3,取消監聽;而通過RAC可以直接實現,RAC的回調是通過block實現的,類似於過程式編程,上下文也更容易理解一些。

    場景:當前類有一個成員變量 NSString *input,當它的值被改變時,發送一個請求。

    實現: 

[objc] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. [RACObserve(self, input)  
  2.     subscribeNext:^(NSString* x){  
  3.         request(x);//發送一個請求  
  4.    }];  

每次input值被修改時,就會調用此block,並且把修改後的值做爲參數傳進來。

 

場景:在上面場景中,當用戶輸入的值以2開頭時,才發請求.

實現:

[objc] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. [[RACObserve(self, input)  
  2.      filter:^(NSString* value){  
  3.          if ([value hasPrefix:@"2"]) {  
  4.              return YES;  
  5.          } else {  
  6.              return NO;  
  7.          }  
  8.      }]  
  9.      subscribeNext:^(NSString* x){  
  10.         request(x);//發送一個請求  
  11.     }];  

場景:上面場景是監聽自己的成員變量,如果想監聽UITextField輸入值變化,框架也做了封裝可以代替系統回調

實現:

[objc] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. [[self.priceInput.rac_textSignal  
  2.      filter:^(NSString *str) {  
  3.          if (str.integerValue > 20) {  
  4.              return YES;  
  5.          } else {  
  6.              return NO;  
  7.          }  
  8.      }]  
  9.      subscribeNext:^(NSString *str) {  
  10. <span style="white-space:pre">    </span>request(x);//發送一個請求  
}];


例2. 同時監聽多個變量變化,當這些變量滿足一定條件時,使button爲可點擊狀態

場景:button監聽 兩個輸入框有值和一個成員變量值,當輸入框有輸入且成員變量爲真時,button爲可點擊狀態

實現:

 

[objc] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. RAC(self.payButton,enabled) = [RACSignal  
  2.                                    combineLatest:@[self.priceInput.rac_textSignal,  
  3.                                                 self.nameInput.rac_textSignal,  
  4.                                                 RACObserve(self, isConnected)  
  5.                                                 ]  
  6.                                    reduce:^(NSString *price, NSString *name, NSNumber *connect){  
  7.                                    return @(price.length > 0 && name.length > 0 && [connect boolValue]);  
  8.                                    }];  

場景:滿足上面條件時,直接發送請求

實現:

[objc] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. [[RACSignal  
  2.                                    combineLatest:@[self.priceInput.rac_textSignal,  
  3.                                                 self.nameInput.rac_textSignal,  
  4.                                                 RACObserve(self, isConnected)  
  5.                                                 ]  
  6.                                    reduce:^(NSString *price, NSString *name, NSNumber *connect){  
  7.                                    return @(price.length > 0 && name.length > 0 && ![connect boolValue]);  
  8.                                    }]  
  9.                              subscribeNext:^(NSNumber *res){  
  10.                                  if ([res boolValue]) {  
  11.                                      NSLog(@"XXXXX send request");  
  12.                                  }  
  13.                              }];  

例3. 類似於生成產-消費

場景:用戶每次在TextField中輸入一個字符,1秒內沒有其它輸入時,去發一個請求。TextField中字符改變觸發事件已在例1中展示,這裏實現一下它觸法的方法,把1秒延時在此方法中實現。

實現:

[objc] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. - (void)showLoading {  
  2.   
  3.     [self.loadingDispose dispose];//上次信號還沒處理,取消它(距離上次生成還不到1秒)  
  4.     @weakify(self);  
  5.     self.loadingDispose = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {  
  6.         [subscriber sendCompleted];  
  7.         return nil;  
  8.     }] delay:1//延時一秒  
  9.     subscribeCompleted:^{  
  10.         @strongify(self);  
  11.         doRequest();  
  12.         self.loadingDispose = nil;  
  13.     }];  
  14. }  

上面代碼看起來挻費解,不過下面一段類似的代碼拆開寫的,會比較容易理解:

[objc] view plain copy
 在CODE上查看代碼片派生到我的代碼片
  1. [self.loadingDispose dispose];  
  2.       
  3.     RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {//BLOCK_1  
  4.         subscriptions++;  
  5.         [subscriber sendNext:@"mytest"];  
  6.         [subscriber sendCompleted];  
  7.         return nil;  
  8.     }];  
  9.       
  10.     loggingSignal = [loggingSignal delay:10];  
  11.       
  12.     self.loadingDispose = [loggingSignal subscribeNext:^(NSString* x){//BLOCK_2  
  13.         NSLog(@"%@",x);  
  14.         NSLog(@"subscription %u", subscriptions);  
  15.     }];  
  16.       
  17.     self.loadingDispose = [loggingSignal subscribeCompleted:^{//BLOCK_3  
  18.         NSLog(@"subscription %u", subscriptions);  
  19.     }];  

loggingSignal在每次被調用subscriibeNext:^(id x)或subscribeCompleted:^方法時(12行和17行),它創建進傳進的參數block_1就會被觸動發,而block_1中的sendNext:方法會調用subscriibeNext:^中對應的block_2, 而block_1中的sendCompleted會調用subscribeCompleted:中對應的block_3

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章