返回

Block 的本质(三)—— 基础类型的变量捕获

IOS

我们一直在探索 Block 的底层结构。上一篇中,我们分析了 。这一次,我们进一步扩展,在 Block 中添加两个参数 a 和 b。按照惯例,我们使用命令

xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc main.m

编译并反汇编 main.m 文件,得到汇编代码如下:

_block_impl_0:
    .align 3
    .quad __block_descriptor_tmp0
    .quad captured_a
    .quad captured_b
    .long 0
    .long 2

__block_descriptor_tmp0:
    .long 0                          // flags
    .long 1                           // isa
    .long _block_func_impl_0           // Implementation pointer
    .long _descriptor                 // Block descriptor

与上一篇相比,汇编代码的变化之处在于,增加了 captured_a 和 captured_b 两个符号。这两个符号分别对应着 Block 中的两个参数 a 和 b。在 Block 的实现中,这两个参数被捕获到了 Block 内部,并存储在了 Block 的数据结构中。

现在,我们来分析一下 Block 数据结构的布局。Block 数据结构的第一个成员是 flags,它是一个 long 型变量,用于存储 Block 的一些标志位,比如 Block 是否可以被复制、是否可以被释放等。第二个成员是 isa,它是一个指向 Block 类对象的指针,用于标识 Block 的类型。第三个成员是 _block_func_impl_0,它是一个指向 Block 实现函数的指针,用于指定当 Block 被调用时应该执行哪个函数。第四个成员是 _descriptor,它是一个指向 Block 符的指针,用于 Block 的一些属性,比如 Block 的捕获变量列表、Block 的返回值类型等。

在 Block 的数据结构中,捕获变量被存储在 flags 之后的连续内存空间中。在本例中,参数 a 和 b 分别被存储在了 captured_a 和 captured_b 两个符号对应的内存空间中。

希望通过这三篇文章,你已经对 Block 的本质有了一个基本的了解。在下一篇文章中,我们将继续深入分析 Block,探讨 Block 的内存管理和释放机制。