一、局部变量截获是 “值截获”
NSInteger number = 30;
NSInteger(^block)(NSInteger) = ^NSInteger(NSInteger n){
return n + number;
};
num = 5;
NSLog(@"%zd", block(10));
这里输出结果是 40,而不是 15,原因是对局部变量 number 的截获是 “值截获”。在 block 里面修改 number,是无效的,并且编译会报错。
NSMutableArray *testArray = [NSMutableArray arrayWithObjects:@"zhang",@"li", nil];
void(^block)(void) = ^{
NSLog(@"%@",testArray);//局部变量
[testArray addObject:@"qian"];
};
[testArray addObject:@"wang"];
testArray = nil;
block();
打印结果为 zhang, li, wang
局部对象变量也是 “值截获”,截获的是值,而不是指针,在外部将其置为 nil,对 block 没有影响。
但是该对象调用方法会影响结果(如NSMutableArray 的 addObject,NSMutableString 的 appendString)。
二、局部静态变量截获是 “指针截获”
static NSInteger number = 30;
NSInteger(^block)(NSInteger) = ^NSInteger(NSInteger n){
return n + number;
};
number = 5;
NSLog(@"%zd", block(10));
输出结果是 15,说明 number = 5 的修改是有效的,即是 “指针截获”。
同时,在 block 里修改变量 number ,也是有效的(如:在 block 里面将 number 修改为 50,输出结果为 60)。
三、全局变量 与 静态全局变量,是 “不截获, 直接取值”
用 clang 编译一下
static NSInteger number3 = 100;
NSInteger number4 = 1000;
- (void)blockTest
{
NSInteger number = 10;
static NSInteger number2 = 1;
__block NSInteger number5 = 10000;
void(^block)(void) = ^{
NSLog(@"%zd",number); //局部变量
NSLog(@"%zd",number2); //静态变量
NSLog(@"%zd",number3); //全局变量
NSLog(@"%zd",number4); //全局静态变量
NSLog(@"%zd",number5); //__block修饰变量
};
number = 50;
number2 = 5;
number3 = 500;
number4 = 5000;
number5 = 50000;
block();
}
输出结果为 : 10 5 500 5000 50000
编译后
struct __Block__blockTest_block_impl_0 {
struct __block_impl impl;
struct __Block__blockTest_block_desc_0* Desc;
NSInteger number;//局部变量
NSInteger *number2;//静态变量
__Block_byref_number5_0 *number5; // by ref//__block修饰变量
__Block__blockTest_block_impl_0(void *fp, struct __Block__blockTest_block_desc_0 *desc, NSInteger _number,
NSInteger *_number2, __Block_byref_number5_0 *_number5, int flags=0) : number(_number), number2(_number2), number5(_number5->__forwarding) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
从 “&_NSConcreteStackBlock” 可以看出,这是一个栈block。局部变量被编译成值形式,而静态变量被编译成指针形式,全局变量并未截获。而__block 修饰的变量也是以指针形式截获的,并且生成了一个新的对象:
struct __Block_byref_number5_0 {
void *__isa;
__Block_byref_number5_0 *__forwarding;
int __flags;
int __size;
NSInteger number5;
};
对于局部变量,如果需要在 block 内部进行赋值操作,需要给局部变量添加__block 修饰符,而对于全局变量、静态变量是不需要添加__block 修饰符的。如果 block 内部访问了 self 或者 self 的成员变量,block 会截获 self。