本文章将记录Objective-C中Block的相关资料,如有错误欢迎指出~
Block的本质
Block本质.pngBlock 实际上就是一个OC对象(结构体中有 isa 指针),这个对象封装了函数,以及函数执行的上下文
Block的变量捕获
为了保证block内部能够正常访问外部的变量,block有一个变量捕获机制。block捕获外部变仅仅只捕获Block闭包里面会用到的值,其他用不到的值,它并不会去捕获。
局部变量
看下简单的代码输出
auto int age = 10;
static int num = 25;
void (^Block)(void) = ^{
NSLog(@"age:%d,num:%d",age,num);
};
age = 20;
num = 11;
Block();
// log age = 10
age = 11
- auto变量
- auto自动变量,离开作用域就销毁,通常局部变量前面自动添加auto关键字。自动变量会捕获到block内部,也就是说block内部会专门新增加一个参数来存储变量的值。 auto只存在于局部变量中,访问方式为值传递。
- static变量
- static 修饰的变量为指针传递,同样会被block捕获。
为什么两种变量会有这种差异呢?
因为自动变量可能会销毁,block在执行的时候有可能自动变量已经被销毁了,那么此时如果再去访问被销毁的地址肯定会发生坏内存访问,因此对于自动变量一定是值传递而不可能是指针传递了。
而静态变量不会被销毁,所以完全可以传递地址。而因为传递的是值得地址,所以在block调用之前修改地址中保存的值,block中的地址是不会变得。所以值会随之改变。
全局变量
因为全局变量无论在哪里都可以访问,所以block不需要捕获全局变量
变量类型总结:
-
局部变量都会被block捕获,自动变量是值捕获,静态变量为地址捕获
-
全局变量则不会被block捕获
Block的类型
OC中,一般Block就分为以下3种类型
-
__NSGlobalBlock__
( _NSConcreteGlobalBlock ),即没有用到外界变量或只用到全局变量、静态变量的block。生命周期从创建到应用程序结束,直到程序结束才会被回收,不过我们很少使用到__NSGlobalBlock__
类型的block,因为这样使用block并没有什么意义。 -
__NSStackBlock__
( _NSConcreteStackBlock ),即只用到外部局部变量、成员属性变量,且没有强指针引用的block。__NSStackBlock__
类型的block存放在栈中,我们知道栈中的内存由系统自动分配和释放,作用域执行完毕之后就会被立即释放,而在相同的作用域中定义block并且调用block似乎也多此一举。 -
__NSMallocBlock__
( _NSConcreteMallocBlock ),即有强指针引用或copy修饰的成员属性引用的block 。存放在堆中,没有强指针引用即销毁,需要我们自己进行内存管理。
Block的循环引用
这篇文章讲的挺不错的Block 与 self 的那点事(iOS)
面试题
面试题请参考 这篇文章 iOS-Block相关面试题
网友评论