iOS4引入了一个新特性,支持
最 左边的int是返回值类型,中间是小括号包围插入符号^及代码块变量的名字,最后又一个小括号,包围着参数的类型(上面例子中只有一个int参数)。等号 右边的代码块声明必须符合左侧的定义。有一点要说明的是,为了方便,可以不声明代码块的返回类型,编译器会从返回语句中做出判断。
    要调用这个代码块,你需要传入一个需要乘3的参数,并接受返回值,像这样:
int result = triple(2);

    下面你将知道如何声明并创建一个需要两个int型参数,将它们相乘然后返回结果的代码块:
int (^multiply)(int, int) = ^(int x, int y) {
    return x * y;
};

    这是如何调用这个代码块:
int result = multiply(2, 3);

    声明代码块变量使我们有机会探讨代码块类型以及如何调用。代码块变量类似函数指针,调用代码块与调用函数相似。不同于函数指针的是,代码块实际上是Objective-C对象,这意味着我们可以像对象一样传递它们。
调用代码块的方法
    在实际中,代码块经常被作为参数传入方法中供其回调。当把代码块作为一个参数时,相比分配一个代码块变量,更通常的做法是作为内联代码块。例如,我们之前看到的例子:view animations 和enumeration。
    苹 果官方已经增加了一些使用代码块的方法到他们的框架中。你也可以写一些使用代码块的API了。例如,我们要创建一个Worker类的使用代码块的类方法, 该方法重复调用代码块指定的次数,并处理代码块每次返回的结果。下面是我们使用内联代码块调用这个方法,代码块负责返回1到10的每个数的三倍。
[Worker repeat:10 withBlock:^(int number) {
    return number * 3;
}];

    这个方法可以将任何接受一个int型参数并返回一个int型结果的代码块作为参数,如果想得到数字的二倍,只需要改变传入方法的代码块。

编写使用代码块的方法
    在第一部分我们留下了一个任务:写一个Work类的调用代码块的类方法,并且重复调用代码块指定的次数,还要处理每次代码块的返回值。如果我们想要得到1到5的三倍的话,那么下面是我们该如何调这个带有内联代码块的方法:
[Worker repeat:5 withBlock:^(int number) {
    return number * 3;
}];
    我 经常这样设计一个类,首先写代码调用一个虚构的方法,这也是在提交之前一种形成API的简单方式,一旦认为这个方法调用正确,我就去实现这个方法。这样, 那个方法的名字是repeat:withBlock:,我认为不合适(我知道在第一部分是叫这个名字,但我已经改变注意了)。这个名字容易使人混淆,因为 该方法实际上并不是重复做相同的事情。这个方法从1迭代到指定的次数,并处理代码块的返回。所以让我们开始正确的重命名它:
[Worker iterateFromOneTo:5 withBlock:^(int number) {
    return number * 3;
}];
    我对这个使用两个参数的方法的名字iterateFromOneTo:withBlock:很满意,一个int型参数表示调用代码块的次数和一个要被调用的代码块参数。现在让我们去实现这个方法。
    对 于初学者,我么该如何声明这个 iterateFromOneTo:withBlock:方法呢?首先我们需要知道所有参数的类型,第一个参数很容易,是个int类型;第二个参数是一个 代码块,代码块是有返回类型的。在这个例子中,这个方法可以接受任何有一个int型参数并返回int型结果的代码块作为参数。下面是实际的代码块类型:
int (^)(int)
    已经有了方法的名字和它的参数类型,我们就可以声明这个方法了。这是Worker类的类方法,我们在worker.h中声明它:
@interface Worker : NSObject {
}
 
+ (void)iterateFromOneTo:(int)limit withBlock:(int (^)(int))block;
 
@end
    第 一眼看去,代码块参数不容易理解。有个要记住诀窍是:在Objective-C中所有的方法参数有两个部分组成。被括起来的参数类型以及参数的名称。这个 例子中,参数的要求是一个是int型和一个是int(^)(int)型的代码块(你可以为参数命名为任意的名字,不一定非得是block)。这个方法的实 现是在Worker.m文件                                     nil];
 
MoviePlayer *player =
    [[MoviePlayer alloc] initWithCallback:^(NSString *title) {
        [movieQueue removeObject:title];
}];
 
for (NSString *title in [NSArray arrayWithArray:movieQueue]) {
    [player playMovie:title];
};

    请 注意代码块使用了本地变量movieQueue,它会成为代码块状态的一部分。当代码块被调用,就会从数组movieQueue中移除一个电影,尽管此时 数组是在代码块作用域之外的。当所有的电影播放完成之后,movieQueue将会是一个空数组。下面是一些需要提及的重要事情:
1、movieQueue变量是一个数组指针,我们不能修改它的指向。我们修改的是它指向的内容,因此不需要使用_block修饰。
2、为了迭代movieQueue数组,我们需要创建一个它的copy,否则如果我们直接使用movieQueue数组,就会出现在迭代数组的同事还在移除它的元素,这会引起异常。
3、如果不使用代码块,我们可以声明一个协议,写一个代理类,并注册这个代理作为回调。很明显该例子使用内联代码块更方便。
4、在不改变MoviePlayer类的前提下可以给他增加新功能。比如另一个开发者可以在看完一部电影后将其分享到twitter或对电影进行评价等。

翻译自 http://pragmaticstudio.com/blog/2010/7/28/ios4-blocks-1

相关文章:

  • 2021-04-08
  • 2021-11-23
  • 2021-11-23
  • 2021-10-16
  • 2021-12-29
  • 2021-10-06
猜你喜欢
  • 2021-12-19
  • 2021-12-29
  • 2021-09-11
  • 2021-05-31
  • 2021-08-04
  • 2021-11-26
  • 2021-10-17
相关资源
相似解决方案