ReactiveCocoa是響應式編程(FRP)在iOS中的一個實現框架,它的開源地址爲:https://github.com/ReactiveCocoa/ReactiveCocoa# ;在網上看了幾篇文章,感覺理論講了很多,但是代碼還是看不太懂,於是自己把它github文檔上的一些使用的經典示例實現了一下,項目中有需要時可以直接搬過去用,用的熟練了再讀源碼也比較容易理解。
例1. 監聽對象的成員變量變化,當成員變量值被改變時,觸發做一些事情。
這種情況其實就是IOS KVO機制使用的場景,使用KVO實現,通常有三個步驟:1,給對象的成員變量添加監聽;2,實現監聽回調;3,取消監聽;而通過RAC可以直接實現,RAC的回調是通過block實現的,類似於過程式編程,上下文也更容易理解一些。
場景:當前類有一個成員變量 NSString *input,當它的值被改變時,發送一個請求。
實現:
- [RACObserve(self, input)
- subscribeNext:^(NSString* x){
- request(x);//發送一個請求
- }];
每次input值被修改時,就會調用此block,並且把修改後的值做爲參數傳進來。
場景:在上面場景中,當用戶輸入的值以2開頭時,才發請求.
實現:
- [[RACObserve(self, input)
- filter:^(NSString* value){
- if ([value hasPrefix:@"2"]) {
- return YES;
- } else {
- return NO;
- }
- }]
- subscribeNext:^(NSString* x){
- request(x);//發送一個請求
- }];
場景:上面場景是監聽自己的成員變量,如果想監聽UITextField輸入值變化,框架也做了封裝可以代替系統回調
實現:
- [[self.priceInput.rac_textSignal
- filter:^(NSString *str) {
- if (str.integerValue > 20) {
- return YES;
- } else {
- return NO;
- }
- }]
- subscribeNext:^(NSString *str) {
- <span style="white-space:pre"> </span>request(x);//發送一個請求
場景:button監聽 兩個輸入框有值和一個成員變量值,當輸入框有輸入且成員變量爲真時,button爲可點擊狀態
實現:
- RAC(self.payButton,enabled) = [RACSignal
- combineLatest:@[self.priceInput.rac_textSignal,
- self.nameInput.rac_textSignal,
- RACObserve(self, isConnected)
- ]
- reduce:^(NSString *price, NSString *name, NSNumber *connect){
- return @(price.length > 0 && name.length > 0 && [connect boolValue]);
- }];
場景:滿足上面條件時,直接發送請求
實現:
- [[RACSignal
- combineLatest:@[self.priceInput.rac_textSignal,
- self.nameInput.rac_textSignal,
- RACObserve(self, isConnected)
- ]
- reduce:^(NSString *price, NSString *name, NSNumber *connect){
- return @(price.length > 0 && name.length > 0 && ![connect boolValue]);
- }]
- subscribeNext:^(NSNumber *res){
- if ([res boolValue]) {
- NSLog(@"XXXXX send request");
- }
- }];
例3. 類似於生成產-消費
場景:用戶每次在TextField中輸入一個字符,1秒內沒有其它輸入時,去發一個請求。TextField中字符改變觸發事件已在例1中展示,這裏實現一下它觸法的方法,把1秒延時在此方法中實現。
實現:
- - (void)showLoading {
- [self.loadingDispose dispose];//上次信號還沒處理,取消它(距離上次生成還不到1秒)
- @weakify(self);
- self.loadingDispose = [[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
- [subscriber sendCompleted];
- return nil;
- }] delay:1] //延時一秒
- subscribeCompleted:^{
- @strongify(self);
- doRequest();
- self.loadingDispose = nil;
- }];
- }
上面代碼看起來挻費解,不過下面一段類似的代碼拆開寫的,會比較容易理解:
- [self.loadingDispose dispose];
- RACSignal *loggingSignal = [RACSignal createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {//BLOCK_1
- subscriptions++;
- [subscriber sendNext:@"mytest"];
- [subscriber sendCompleted];
- return nil;
- }];
- loggingSignal = [loggingSignal delay:10];
- self.loadingDispose = [loggingSignal subscribeNext:^(NSString* x){//BLOCK_2
- NSLog(@"%@",x);
- NSLog(@"subscription %u", subscriptions);
- }];
- self.loadingDispose = [loggingSignal subscribeCompleted:^{//BLOCK_3
- NSLog(@"subscription %u", subscriptions);
- }];
loggingSignal在每次被調用subscriibeNext:^(id x)或subscribeCompleted:^方法時(12行和17行),它創建進傳進的參數block_1就會被觸動發,而block_1中的sendNext:方法會調用subscriibeNext:^中對應的block_2, 而block_1中的sendCompleted會調用subscribeCompleted:中對應的block_3