Block本质
本质是一个OC对象,编译之后是一个结构体包含isa指针,block中封装了调用的函数和调用环境。调用环境值variables
是block捕获的变量(如果block中访问了一些需要被捕获的变量,例如局部变量)
block的变量捕获机制:
- 局部变量,
auto
临时变量会捕获到block内部,且用的值传递。static
会捕获,用的指针传递。 - 全局变量,不会捕获,block运行的时候会直接访问
auto临时变量代表 autorelease的在一个作用域内的临时变量
其中FuncPtr指的block函数的指针。
block分为3种类型,分别为__NSGlobalBlock__
,__NSStackBlock__
,__NSMallocBlock__
,分为位于以下内存区域,那么什么样的block会属于什么样的类型?
上图表示不同的block因为操作的变量类型不一样,所以block类型也不一样。因为auto变量是临时变量会存在stack
中自动销毁,所以相应block就是stack
。没访问auto变量则存在常量区global
。
为什么block用copy修饰?
由于stackblock
在栈中,且捕获的是在栈中的变量,如果变量销毁,有可能block访问的就的数据就是野指针,所以需要将stackblock
通过调用copy方法转为mallocblock
即保存到堆中,保证由用户自己创建自己销毁,不会造成程序异常。所以block变量用copy修饰或者直接调用copy方法
block如果捕获变量
当block内部访问了对象类型的auto变量时:
- 如果block在栈上,则不会对auto变量强引用
- 如果block被拷贝到堆上:会调用block内部的copy函数(
__block_object_assgin
),会根据对象的修饰符__strong, __weak等作出强引用或弱引用 - 如果block从堆上移除:调用block内部dispose函数,对变量release
__block与__weak、__strong
__block
修饰一个变量会把他包装成一个结构体对象,其中的一个属性就是这个变量。且这个结构体对象会把捕获的对象进行引用,根据对象前面是否使用__weak
和__strong
决定是弱引用还是强引用。
block中的forwarding
指针是指向自己位于堆中的地址,如果修饰的是对象,block中还会增加2个内存管理方法,copy
和dispose
__weak 和 __strong 目的是在变量被block捕获的时候以什么引用方式。
循环引用问题:
对象 强引用 block; block 强引用 对象 导致无法释放, 解决办法是将其中一条链路变为弱引用,则能完成释放。