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的用法有很多种,最常用的有 回调 和 遍历 。这篇主要说 回调
-
回调
什么是回调
在计算机程序设计中,回调函数,或简称回调(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"