最认真的Block
block的本质:
1.block的本质其实就是一个oc对象(内部有isa指针),内部封装了函数调用和函数调用(函数参数)的oc对象。
2.block的底层结构如图:
block的底层结构.png
2.block捕获机制:
为了保证block能够正常访问外部的变量,block有个变量捕获机制。
block捕获机制.jpg3.block类型:
block类型block在内存中的分配
-
总结:
image.png
每一种block在调用copy之后的类型:
image.png
4.block的copy
在ARC环境下,编译器会根据情况自动将栈上的block复制到堆上,比如以下情况:
-
block作为函数返回值时:
1.将block赋值给__strong指针时
2.block作为Cocoa API中方法名含有usingBlock的方法参数时
3.block作为GCD API的方法参数时 -
MRC下block属性的建议写法
@property (copy, nonatomic) void (^block)(void); -
ARC下block属性的建议写法
@property (strong, nonatomic) void (^block)(void);
@property (copy, nonatomic) void (^block)(void);
5.对象类型的auto变量
-
当block内部访问了对象类型的auto变量时
如果block是在栈上,将不会对auto变量产生强引用 -
如果block被拷贝到堆上
- 会调用block内部的copy函数
copy函数内部会调用_Block_object_assign函数
_Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用
-
如果block从堆上移除
会调用block内部的dispose函数
dispose函数内部会调用_Block_object_dispose函数
_Block_object_dispose函数会自动释放引用的auto变量(release)
image.png
6.__block修饰符和内存管理
- __block修饰符的作用:
__block可以用于解决block内部无法修改auto变量值的问题
__block不能修饰全局变量、静态变量(static)
编译器会将__block变量包装成一个对象
-
内存管理:
一.当block在栈上时,并不会对__block变量产生强引用
二.当block被copy到堆时:
1.会调用block内部的copy函数
2.copy函数内部会调用_Block_object_assign函数
3._Block_object_assign函数会对__block变量形成强引用(retain) -
被__block修饰的对象类型
1.当__block变量在栈上时,不会对指向的对象产生强引用
2.当__block变量被copy到堆时
3.会调用__block变量内部的copy函数
copy函数内部会调用_Block_object_assign函数
_Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)
如果__block变量从堆上移除
会调用__block变量内部的dispose函数
dispose函数内部会调用_Block_object_dispose函数
_Block_object_dispose函数会自动释放指向的对象(release)
7.解决循环引用问题 - ARC
1.用__weak、__unsafe_unretained解决:
__weak 对象销毁时系统会自动置为nil,__unsafe_unretained会产生野指针
image.png
2.用__block解决(必须要调用block):
image.png
8.解决循环引用问题 - MRC
1.用__unsafe_unretained解决:
image.png
2.用__block解决:
image.png