美文网首页
block(二)-- 底层分析

block(二)-- 底层分析

作者: Ray_lawq | 来源:发表于2019-05-22 23:28 被阅读0次

    block(一):https://www.jianshu.com/p/b83574a8ef80
    连接上文拿到block 的C++ 文件,内容如下:

    那么我们第二章就慢慢分析这个C++文件。

    __block 修饰的局部变量变成一个__Blcok_byref_c_0 的结构体,让我们看看这个结构体的实现:

    1. 我们可以很清楚的看到有一个 __frowatding 这个变量,它有什么用呢?
      它是一个桥梁,在Block 内部,先找到这个结构体,通过这个结构体的frowatding成员变量找到外部的局部变量

    2. 那么__frowatding在不同类型的Block指向有什么不同呢:

    这样通过__forwarding,无论是在block内部还是外部,不管是堆上还栈,都能访问到同一个__block修饰的变量。

    __testBlockA_block_func_0(是Block 内部的方法(代码块))

    block 实现方法(__testBlockA_block_impl_0),入参中有2个默认参数(方法): __testBlockA_block_func_0和__main_block_desc_0_DATA

    结论:
    1. 局部变量不能在block 里边修改值,__block修饰的和全局变量可以。
    2. 验证了__forwarding在__block 结构体的指向(上边__forwarding的指向结论)

    另一参数(方法): __main_block_desc_0_DATA

    我们可以看到__main_block_desc_0中存储着两个参数:reserved
    和Block_size;并且reserved赋值为0而Block_size则存储着__main_block_impl_0的占用空间大小。最终将__main_block_desc_0结构体的地址传入__main_block_func_0中赋值给Desc。

    让我们在看看__testBlockA_block_impl_0 主方法里边的实现:

    首先我们看一下__block_impl第一个变量就是__block_impl结构体。 来到__block_impl结构体内部

    我们可以发现__block_impl结构体内部就有一个isa指针。因此可以证明block本质上就是一个oc对象。而在构造函数中将函数中传入的值分别存储在__main_block_impl_0结构体实例中,最终将结构体的地址赋值给block。

    接着通过上面对__main_block_impl_0结构体构造函数三个参数的分析我们可以得出结论:

    1. __block_impl结构体中isa指针存储着&_NSConcreteStackBlock地址,可以暂时理解为其类对象地址,block就是_NSConcreteStackBlock类型的。
    2. block代码块中的代码被封装成__main_block_func_0函数,FuncPtr则存储着__main_block_func_0函数的地址。
    3. Desc指向__main_block_desc_0结构体对象,其中存储__main_block_impl_0结构体所占用的内存。

    那么block是怎么执行的?

    通过上述代码可以发现调用block是通过block找到FunPtr直接调用,通过上面分析我们知道block指向的是__main_block_impl_0类型结构体,但是我们发现__main_block_impl_0结构体中并不直接就可以找到FunPtr,而FunPtr是存储在__block_impl中的,为什么block可以直接调用__block_impl中的FunPtr呢?
    重新查看上述源代码可以发现,(__block_impl *)block将block强制转化为__block_impl类型的,因为__block_impl是__main_block_impl_0结构体的第一个成员,相当于将__block_impl结构体的成员直接拿出来放在__main_block_impl_0中,那么也就说明__block_impl的内存地址就是__main_block_impl_0结构体的内存地址开头。所以可以转化成功。并找到FunPtr成员。
    上面我们知道,FunPtr中存储着通过代码块封装的函数地址,那么调用此函数,也就是会执行代码块中的代码。并且回头查看__main_block_func_0函数,可以发现第一个参数就是__main_block_impl_0类型的指针。也就是说将block传入__main_block_func_0函数中,便于重中取出block捕获的值。

    此时已经基本对block的底层结构有了基本的认识,上述代码可以通过一张图展示其中各个结构体之间的关系。

    block底层的数据结构也可以通过一张图来展示

    参考文章:https://www.jianshu.com/p/92f15fc9301a

    相关文章

      网友评论

          本文标题:block(二)-- 底层分析

          本文链接:https://www.haomeiwen.com/subject/astmzqtx.html