清秋梧桐

导航

Block的用法总结——写回调

Block 用法总结 (I)


block是个什么玩意儿

Block是Apple Inc.为C、C++以及Objective-C添加的特性,使得这些语言可以用类lambda表达式的语法来创建闭包 ——维基百科

A block is an anonymous inline collection of code, and sometimes also called a "closure". ——Apple文档

闭包就是能够读取其它函数内部变量的函数。

这里简单总结一下用法。block的用法有很多种,最常用的有 回调遍历 。这篇主要说 回调

  1. 回调

    什么是回调

    在计算机程序设计中,回调函数,或简称回调(Callback),是指通过函数参数传递到其它代码的,某一块可执行代码的引用。这一设计允许了底层代码调用在高层定义的子程序。 ——维基百科

    回调就是说,我一个操作执行完成之后,提供给调用者一个接口,供调用者定义一些操作。obj-C的代理模式就是典型的回调。

    举个简单的block例子:

     @interface People : NSObject
    
     -(void)runningOutOfMoneyUsingBlock:(void (^)(void))aBlok;
    
     @end
    
    
     @implementaiton People
    
     -(void)runningOutOfMoneyUsingBlock:(void (^)(void))aBlok
     {
         NSLog(@"I have run out of my money");
         aBlock();     //(1)
     }
    
     @end
    

    这个时候, 就定义了一个带block参数的方法。这是一个很简单的block参数, 没有返回值, 没有参数。

    当我们调用这个方法的时候,只需这样操作:

     Peopeo *aPeople = [[People alloc] init]];
     [aPeople runningOutOfMoneyUsingBlock:^{
    
         NSLog(@"Earn more money!");
    
     }];
    

    这时在执行People类方法的时候,执行结果如下:

     “I have run out of my mondy”
     "Earn more money!"
    

    很好理解,People的类方法有一个block参数。调用者在调用该方法的时候为block参数定义了若干操作(这里是输出一句话),然后将这些操作作为参数传递给类方法内部执行.调用者所定义的这些操作执行的位置,取决于"(1)"所处的位置。

    如果将类方法的实现改变为:

     -(void)runningOutOfMoneyUsingBlock:(void (^)(void))aBlok
     {
         aBlock();     //(1)
         NSLog(@"I have run out of my money");
     }
    
     @end
    

    那么运行结果就会变为:

     "Earn more money!"
     “I have run out of my money”
    

    下面来说一说block 带参数 的情况,有People类方法定义如下:

     @interface People : NSObject
    
     -(void)runningOutOfMoneyUsingBlock:(void (^)(int a, int b))aBlok;
    
     @end
    
     @implementaiton People
    
     -(void)runningOutOfMoneyUsingBlock:(void (^)(int a, int b))aBlok
     {
         NSLog(@"I have run out of my money");
         int a = 10;
         int b = 50
         aBlock(a,b);     //(2)
     }
    
     @end
    

    在这个类方法中,对之前的People类方法的block参数进行了扩展,加入了两个整形参数:a和b。在调用block之前为a和b赋值并且传给了block,形如(2)。

    这个时候,当我们在调用这个类方法的时候,就会出现这样的情况:

     Peopeo *aPeople = [[People alloc] init]];
     [aPeople runningOutOfMoneyUsingBlock:^(int a, int b){
    
         NSLog(@"a = %d, b = %d", a, b);
    
     }];
    

    执行结果如下:

     "Earn more money!"
     "a = 10, b = 50"
    

    不难看出,People将自己内部的两个局部变量, 通过block传递给了调用者。这一点很好理解,想想我们经常使用的 代理方法 就可以了。

    以UITableView的代理方法为例,代理方法定义如下

     - (void)tableView(UITableView *):tableView didSelectRowAtIndexPath:(NSIndexPath)indexPath;
    

    这个方法用来给某个section指定行数。私以为这个方法可以换为如下block实现。

     @interface UITableView (WithBlock)
    
     -(void)didSelectRowAtIndexPathUsingBlock:(void (^)(UItableView *tableView, NSIndxPath *indexPath))selectBlock;
    
     @end
    
    
     @implementation UITableView (WithBlock)
    
     -(void)didSelectRowAtIndexPathUsingBlock:(void (^)(UItableView *tableView, NSIndxPath *indexPath))selectBlock
     {
         //some other code
         ...
         if(selectBlock) {
             selectBlock(self, indexPath);
         }
    
         …
         //some other code
     }
    
     @end
    

    好吧, 我承认这里给出这样的方法有点儿蹩脚,仅仅是为了对比Block和代理的相似之处。回想一下代理的实现,block是一样的原理。

    block还可以有返回值,将block在调用者处执行的结果返回给方法本身。例如,再对以上实例方法进行扩展,代码如下:

      @interface People : NSObject
    
     -(void)runningOutOfMoneyUsingBlock:(int (^)(int a, int b))aBlok;
    
     @end
    
     @implementaiton People
    
     -(void)runningOutOfMoneyUsingBlock:(int (^)(int a, int b))aBlock
     {
         NSLog(@"I have run out of my money");
         int a = 10;
         int b = 50
         int m = 0;
         if(aBlock)
         {
             m = aBlock(a,b);     //(2)
         }
         NSLog(@"aBlock的返回值为:%d",m);
    
     }
    
     @end
    

    调用该方法:

     [aPeople runningOutOfMoneyUsingBlock^(int a, int b){
         return a + b;
     }];
    

    执行结果为:

     "I have run out of money"
     "aBlock的返回值为:60"
    

posted on 2013-04-17 00:02  清秋梧桐  阅读(2075)  评论(0编辑  收藏  举报