block 和 ReactiveCocoa的理解(一)

1. block的最大用處:回調(callback)

雖然接觸iOS已經8個月了,block 作為Objective C中對于回調(callback)的實現,理解起來還是有點模棱兩可。在《Pro Multithreading and Memory Management for iOS and OS X》書中,Kazuki Sakamoto 對block的定義是:

擁有自動變量(可以在block聲明的語義環境里捕捉變量的狀態)的匿名(使函數體(code)成為和數據(data)一樣的一等公民,作為函數調用時輸入的實參(argument))函數。

我發現,在大部分應用block的場景,這樣的定義不夠sharp,使人模棱兩可。我用我自己的理解重定義block:

擁有自動變量(可以在block聲明的語義環境里捕捉變量的狀態)的匿名(使函數體(code)成為和數據(data)一樣的一等公民,作為函數調用時輸入的實參(argument))回調(callback,等待被調用)函數。

回調(callback)兩個字把block在大部分場景應用時的扮演的角色給準確描述。下面我舉一個簡單的例子來解釋回調。NSArray的實例方法 *- enumerateObjectsUsingBlock:(void (^ )(id obj, NSInteger idx, BOOL *stop))block 是一個用block實現數組枚舉的方法。下面是該方法的簡單應用:

NSArray *cities = @[@"Beijing", @"Shanghai", @"Guangzhou", @"Shenzhen",@"Hong Kong"];
[cities enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
    NSLog(@"index: %lu, obj: %@, stop: %d",(unsigned long)idx,obj,*stop);
    if(idx == 3){
        *stop = YES;
    }
}];

//這是一個再簡單不過的數組枚舉。輸出為:

2016-01-06 22:52:18.143 Chapter00_Block implmenetaion[18596:780185] index: 0, obj: Beijing, stop: 0 
2016-01-06 22:52:18.144 Chapter00_Block implmenetaion[18596:780185] index: 1, obj: Shanghai, stop: 0 
2016-01-06 22:52:18.144 Chapter00_Block implmenetaion[18596:780185] index: 2, obj: Guangzhou, stop: 0 
2016-01-06 22:52:18.144 Chapter00_Block implmenetaion[18596:780185] index: 3, obj: Shenzhen, stop: 0

那么,如何理解上面block的新定義里的回調呢。由于apple 自己里大部分類的實現是保密的,我們來自己定義一個方法來簡單實現下這個- enumerateObjectsUsingBlock:方法的功能。首先來給NSArray添加一個名為Enumeration的category,加入以下代碼。

NSArray+Enumeration.h

#import <Foundation/Foundation.h> 
@interface NSArray (Enumeration) 
- (void)customizedEnumerateWithBlock:(void(^)(id obj, NSInteger index, BOOL *stop))block; 
@end

NSArray+Enumeration.m

#import "NSArray+Enumeration.h" 
@implementation NSArray (Enumeration) 
-(void)customizedEnumerateWithBlock:(void (^)(id, NSInteger, BOOL *))block{ 
    BOOL stop = false; for(int i = 0; i < self.count; ++i){ 
        block(i,[self objectAtIndex:i],&stop); 
        if(stop) break;
    }
 }  
@end

如果你把cities的數組枚舉方法換成這個,那么輸出是一樣的。

NSArray *cities = @[@"Beijing", @"Shanghai", @"Guangzhou", @"Shenzhen", @"Hong Kong"];
[cities customizedEnumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL * stop) {
    NSLog(@"index: %lu, obj: %@, stop: %d",(unsigned long)idx,obj,*stop);
    if(idx == 3){
        *stop = YES;
    }
}];

//輸出為:

2016-01-06 22:52:18.143 Chapter00_Block implmenetaion[18596:780185] index: 0, obj: Beijing, stop: 0 
2016-01-06 22:52:18.144 Chapter00_Block implmenetaion[18596:780185] index: 1, obj: Shanghai, stop: 0 
2016-01-06 22:52:18.144 Chapter00_Block implmenetaion[18596:780185] index: 2, obj: Guangzhou, stop: 0 
2016-01-06 22:52:18.144 Chapter00_Block implmenetaion[18596:780185] index: 3, obj: Shenzhen, stop: 0

由此可見,我們自己實現的數組枚舉能實現原本的數組枚舉方法。在- customizedEnumerateWithBlock: 的實現里,回調了block這個函數。因此若有方法里有block體作為參數,則意味著這個方法在調用其他函數的同時,這個block在等待將來被調用。那么該block什么時候被調用呢(這里是for 循環語句里),在實際應用block場景里,block的調用更多地是簡化網絡請求,delegate等。

因此“回調”是block我個人認為最大的用處。

2. ReactiveCocoa的subscription原理

作為響應式函數編程的iOS實現,ReactiveCocoa將iOS編程帶入了一個新紀元,其最大的貢獻在于:

統一消息傳遞機制:iOS 開發中有著各種消息傳遞機制,包括 KVO、Notification、delegation、block 以及 target-action 方式。

ReactiveCocoa的入門可以參考
http://www.raywenderlich.com/62699/reactivecocoa-tutorial-pt1
http://www.raywenderlich.com/62796/reactivecocoa-tutorial-pt2

這里我著重要說的是ReactiveCocoa (訂閱)subscription的實現原理--block回調的應用。在ReactiveCocoa里,RACSignal, RACSubscriber, RACDisposal 是最核心的三個類。下面我們就一個簡單的例子深入理解subscription的實現原理,見下面代碼:

-(RACSignal *)signInSignal {
  // part 1:[RACSignal createSignal]來獲得signal
  return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
           [self.signInService signInWithUsername:self.usernameTextField.text
                                         password:self.passwordTextField.text
                                         complete:^(BOOL success) {
  // part 3: 進入didSubscribe,通過[subscriber sendNext:]來執行next block
             [subscriber sendNext:@(success)];
             [subscriber sendCompleted];
            }];
            return nil;
          }];
}

// part 2 : [signal subscribeNext:]來獲得subscriber,然后進行subscription
[[self signInSignal] subscribeNext:^(id x) { 
    NSLog(@"Sign in result: %@", x); 
}];
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,251評論 4 61
  • Swift版本點擊這里歡迎加入QQ群交流: 594119878最新更新日期:18-09-17 About A cu...
    ylgwhyh閱讀 25,571評論 7 249
  • 對保齡球的印象,當然就是電視屏幕里的那些。差不多,和高爾夫球是一個級別的運動項目,對我來說。昨天下班后公司活動是打...
    一只默閱讀 621評論 0 0
  • 我就是故事里的老男孩 事實上,這些年來我在網絡寫過了不少隨筆,雜文,小說。我唯一記得清楚的是,我從來沒有一次以自己...
    周適魯閱讀 366評論 7 21
  • 周末睡個大懶覺,起來做點想吃的菜,然后窩在沙發看電視吃零食。就這樣當一個廢物的感覺,真棒!
    Candy果閱讀 203評論 5 2