block简介
block 其实就是一个值,并且有类型。可以当做 int float 或者 Objective-C对象,也可以赋给变量,然后像使用其他变量那样使用它。只不过定义语法有些特殊。
下面就是一个block:
void (^someBlock)() = ^{
//block implementation here
};
这段代码定义了一个名为someBlock的变量。由于变量名写在正中间,所以看上去有点怪。
return_type (^block_name)(parameters)
从左到右依次表示返回类型return_type
、block的名字block_name
、参数parameters
按照这种格式定义一个:
int (^addBlock)(int a,int b) = ^(int a,int b) {
return a+b;
};
定义好之后,就可以像函数那样使用了:
int result = addBlock(1,2); //最终打印result 值为3
block在其声明的范围内,所有的变量都可以为其所获。这也就是说,在它声明范围内的全部变量,在block的里面依然可以使用,block也可以叫做块
,代码块
。使用外部的变量如下:
int external = 1;
int (^addBlock)(int a,int b) = ^(int a,int b) {
return a+b + external;
};
// 调用
int result = addBlock(1,2); //最终打印result 值为4
默认情况下,block使用外部的变量是不可以修改的。如果要修改需要添加修饰符 __block
。
__block NSInteger count = 0;
NSInteger (^numBlock)() = ^{
count = 1;
return count;
};
栈块及堆块(block)
定义块的时候,其所占的内存区域是非配在栈中的。这就是说,块只在定义它的那个范围内有效。例如下面这样就有危险:
void (^block) ();
if(/* some condition*/) {
block = ^{
NSLog(@"Block A");
};
} else {
block = ^{
NSLog(@"Block B");
};
}
block();
定义在if
及else
语句中的两个块都分配在栈内存中。编译器会给每个块分配好栈内存,然而等离开相应的范围之后,编译器有可能把分配给块的内存覆写掉。于是,这两个块只能保证在if
及else
语句范围内有效。这样写出来的代码可以编译,但是运行起来时而正确,时而错误。若编译器未覆写待执行的块,则程序照常运行,若覆写,则程序崩溃。
为解决此问题,可给块对象发送copy
消息以拷贝之。这样的话,就可以把块从栈复制到堆上。拷贝后的块,可以在定义它的那个范围之外使用,如下:
void (^block) ();
if(/* some condition*/) {
block = [^{
NSLog(@"Block A");
} copy];
} else {
block =[ ^{
NSLog(@"Block B");
} copy];
}
block();
参考
《Effective Objective-C 2.0》
网友评论