本质
- block本质是一个oc对象,内部有isa指针
- block是封装了函数和函数调用环境的oc对象
- block内部有 isa,flag,funcptr,descriptor( size copy dispose函数),捕获的变量 variavles
类型
- 未捕获变量 NSConcreteGlobalBlock (NSGlobalBlock)(数据区.data区)
- 捕获了auto变量且进行了 copy,NSConcreteMallocBlock (堆)
- 捕获了auto变量且未进行 copy,NSConcreteStackBlock(栈)
捕获变量
- 对于 auto 值捕获
- 对于 static 指针捕获
- 对于全局变量 直接访问
捕获变量内存管理
- block在栈上,不回产生强引用
- block被copy到堆上
- 会调用block内部 copy 函数,内部调用 _Block_object_assign函数
- _Block_object_assign函数会根据auto变量外部的修饰符,作出对应的操作,形成 retain 引用 或者 weak 引用
- _Block_object_assign也会对__block修饰对象强引用
- block从堆上移除
- 调用block内部 dispose 函数,内部调用 _Block_object_dispose函数
- _Block_object_dispose函数会释放引用的auto变量
-- _Block_object_assign也会对__block修饰对象释放
Block的copy
- ARC下,很多情况会自动进行block的copy,进行内存管理
- block作为函数返回值
- cocoa API中包含 usingBlock的方法参数
- 作为GCD API
- ARC 使用strong 和 copy对block进行修饰皆可
_ _block修饰符
- __block为了解决内部无法修改 auto变量
- __block修饰的变量会被包装成对象
- 对象内有 isa,forwarding,size,age(变量)
- 当block在栈上,不会对__block产生强引用
- _Block_object_assign会对__block形成强引用,同理 _Block_object_dispose一样
- MRC下,不会对 __block修饰对象reatin
_ _block的 _ _ forwarding
- 栈内部的block的 forwarding指向自己
- 当copy到堆上后,栈上的forwarding指向堆上的block,堆上block指向自己,这样能保证不管栈还是堆,访问的变量都是同一份
解决循环引用
- ARC
- __weak (__unsafe_unretained不推荐)
- __block (需要调用block且在block内部self=nil)
- MRC
- __unsafe_unretained
- __block