5、block底层

93 阅读2分钟

探究block的底层,探究block的本质。

新建一个项目,创建一个简单的block。

接下来进行通过xcrun编译生成指定cpp文件,在文件的最后可以找到有关于block的部分,main方法中只有这几部分内容,那么这部分就一定是block的定义

通过_impl可以找到对应实现,如下图所示:

通过上图所示可以发现block底层实现是个结构体,查看第一个结构体变量,可以看到是一个包含isa指针的结构体,最后可以发现block是一个包含isa指针的对象,也只有对象才可能包含isa指针。

进阶:block的捕获机制:如果变量是局部的分为两种情况,auto和static类型,默认为auto,auto会以值的形式直接被block捕获,而static则会被捕获指针,不多说,直接上比较

可以看到height是是指针形式被捕获,age是普通的值,所以age不会被改变,而height可以。

全局变量则不会被捕获,接下来进行验证

通过上两幅图可以发现,打印的值是最新的,cpp源码中block结构体并没有捕获任何变量,由此可以确定block并没有捕获全局变量,无论是auto类型还是static类型。

进阶2:block的三种类型__NSGlobalBlock__、NSStackBlock__和__NSMallocBlock

block会在什么时候是这三种类型?第一Global:在访问不是auto类型的变量时,上图验证

接下来的两种情况,Stack类型,访问auto类型的变量,并且关闭自动引用计数

在自动引用计数没有干预的情况下,访问auto类型局部变量,block类型为Stack

在自动引用计数或者进行copy操作,此时block才是Malloc类型,这种做法的目的是将block copy一份到堆空间中,堆空间是由程序员自行管理,保证了不过早销毁

进阶3:block中,默认情况无法修改auto类型局部变量的原因

默认情况下block内部是不可以修改auto类型外部变量

原因很简单,作用域不同,存放的内存位置不同,此时的的age被捕获到了堆上,而外部的age是在栈上

_ _ block会把变量包装成对象,使block捕获地址通过 _ _ forwarding指向自己取出变量值, _ _block包装后结构如下图所示