1.auto变量
int a = 10;
void (^block)(void) = ^{
NSLog(@"%d", a);
};
block();
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int a; //这是新加入的成员变量
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int _a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
在_main_block_impl_0这个结构体中我们发现多了一个int类型的成员变量a,在结构体的构造函数中多了一个参数int _a,并且用这个int _a去初始化成员变量a,所以传入了自动变量a用来初始化_main_block_impl_0的成员变量a,_main_block_impl_0的成员变量a就被赋值为10了。
2.static变量
static int a = 10;
void (^block)(void) = ^{
NSLog(@"%d", a);
};
block();
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
int *a;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int *_a, int flags=0) : a(_a) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
在结构体多了一个指针类型的成员变量int *a,然后在构造函数中,将传递过来的&a,赋值给这个指针变量。也就是说,在_main_block_impl_0这个结构体中多了一个成员变量,这个成员变量是指针,指向a这个变量。所以当a变量的值发生变化时,能够得到最新的值。
3.全局变量
int height = 10;
int main(int argc, char * argv[]) {
@autoreleasepool {
void (^block)(void) = ^{
NSLog(@"%d", height);
};
block();
return 0;
}
}
struct __main_block_impl_0 {
struct __block_impl impl;
struct __main_block_desc_0* Desc;
__main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) {
impl.isa = &_NSConcreteStackBlock;
impl.Flags = flags;
impl.FuncPtr = fp;
Desc = desc;
}
};
在_main_block_impl_0结构体中并没有增加成员变量,所以可以得出结论,block并不会捕获全局变量。
总结
变量类型 | 是否捕获到block内部 | 访问方式 |
---|---|---|
局部auto变量 | 是 | 值传递 |
局部static变量 | 是 | 指针传递 |
全局变量 | 否 | 直接访问 |
思考:为什么对于不同类型的变量,block的处理方式不同呢?
这是由变量的生命周期决定的。对于自动变量,当作用域结束时,会被系统自动回收,而block很可能是在超出自动变量作用域的时候去执行,如果之前没有捕获自动变量,那么后面执行的时候,自动变量已经被回收了,得不到正确的值。对于static局部变量,它的生命周期不会因为作用域结束而结束,所以block只需要捕获这个变量的地址,在执行的时候通过这个地址去获取变量的值,这样可以获得变量的最新的值。而对于全局变量,在任何位置都可以直接读取变量的值。
网友评论