为了保证block内部可以正常访问外部的变量,block有一个变量捕获机制。bash
在上一篇代码中咱们已经了解过block对age变量的捕获。 auto自动变量,离开做用域就销毁,局部变量前面自动添加auto关键字。自动变量会捕获到block内部,也就是说block内部会专门新增长一个参数来存储变量的值。 auto只存在于局部变量中,访问方式为值传递,经过上述对age参数的解释咱们也能够肯定确实是值传递。函数
static 修饰的变量为指针传递,一样会被block捕获。ui
接下来分别添加auto修饰的局部变量和static修饰的局部变量,重看源码来看一下他们之间的差异:spa
auto int a = 10;
static int b = 10;
void(^block)(void) = ^{
NSLog(@"hello, a = %d, b = %d", a,b);
///打印 hello, a = 10, b = 20
};
a = 20;
b = 20;
block();
复制代码
经过命令行咱们查看源代码:命令行
从上述源码中能够看出,a,b两个变量都有捕获到block内部。可是a传入的是值,而b传入的则是地址。3d
为何两种变量会有这种差别呢,由于自动变量可能会销毁,block在执行的时候有可能自动变量已经被销毁了,那么此时若是再去访问被销毁的地址确定会发生坏内存访问,所以对于自动变量必定是值传递而不多是指针传递了。而静态变量不会被销毁,因此彻底能够传递地址。而由于传递的是值得地址,因此在block调用以前修改地址中保存的值,block中的地址是不会变得。因此值会随之改变。指针
咱们以一样的方式来研究下block是否捕获全局变量code
int a = 10;
static int b = 10;
int main(int argc, const char * argv[]) {
@autoreleasepool {
void(^block)(void) = ^{
NSLog(@"hello, a = %d, b = %d", a,b);
/// 打印hello, a = 20, b = 20
};
a = 20;
b = 20;
block();
}
return 0;
}
复制代码
源代码:cdn
经过上述代码能够发现,__main_block_imp_0并无添加任何变量,所以block不须要捕获全局变量,由于全局变量不管在哪里均可以访问。 局部变量由于跨函数访问因此须要捕获,全局变量在哪里均可以访问 ,因此不用捕获。 因此用下面这张图作个总结:blog
总结:局部变量都会被block捕获,自动变量是值捕获,静态变量为地址捕获。全局变量则不会被block捕获
疑问思考:如下代码中block是否会捕获变量呢?
#import "Person.h"
@implementation Person
- (void)test
{
void(^block)(void) = ^{
NSLog(@"%@",self);
};
block();
}
- (instancetype)initWithName:(NSString *)name
{
if (self = [super init]) {
self.name = name;
}
return self;
}
@end
复制代码