iOS底层:Block


block的本质

block本质上也是一个OC对象,它内部也有个isa指针。block是封装了函数调用以及函数调用环境的OC对象。
底层结构

block的变量捕获(capture)

为了保证block内部能够正常访问外部的变量,block有个变量捕获机制。
变量捕获机制

例子:
内部捕获age变量

block的类型

block有3种类型,可以通过调用class方法或者isa指针查看具体类型,最终都是继承自NSBlock类型。
1、NSGlobalBlock ( _NSConcreteGlobalBlock )全局区
2、NSStackBlock ( _NSConcreteStackBlock )堆区
3、NSMallocBlock ( _NSConcreteMallocBlock )栈区

block类型和环境

每一种类型的block调用copy后的结果如下所示
copy结果

对象类型的auto变量

当block内部访问了对象类型的auto变量时:

如果block是在栈上:将不会对auto变量产生强引用。
如果block被拷贝到堆上:

1、会调用block内部的copy函数。
2、copy函数内部会调用_Block_object_assign函数。
3、_Block_object_assign函数会根据auto变量的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用。

如果block从堆上移除

1、会调用block内部的dispose函数。
2、dispose函数内部会调用_Block_object_dispose函数。
3、Block_object_dispose函数会自动释放引用的auto变量(release)。

__block修饰符

__block可以用于解决block内部无法修改auto变量值的问题,__block不能修饰全局变量、静态变量(static),编译器会将__block变量包装成一个对象。

例子
修饰age对象

__block的内存管理

当block在栈上时,并不会对__block变量产生强引用。
当block被copy到堆时,会调用block内部的copy函数,copy函数内部会调用_Block_object_assign函数,_Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)。

copy到堆过程

当block从堆中移除时,会调用block内部的dispose函数,dispose函数内部会调用_Block_object_dispose函数,_Block_object_dispose函数会自动释放引用的__block变量(release)。
堆中移除

__block的__forwarding指针

复制到堆

循环引用问题

ARC

用__weak、__unsafe_unretained解决
__weak、__unsafe_unretained

用__block解决(必须要调用block)
__block

MRC

用__unsafe_unretained解决
用__block解决

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容