参考:唐巧的博客
objective-c的底层是用C++实现的。
我们用clang命令是可以把objective-c代码转码为C++代码的。这成为了我们分析block实现原理的工具:
objective-c中一共有三种类型的block:
1._NSConcreteGlobalBlock
2._NSConcreteStackBlock
3._NSConcreteMallocBlock
NSConcreteGlobalBlock
全局的静态 block,不会访问任何外部变量。
NSConcreteStackBlock
保存在栈中的 block,当函数返回时会被销毁。
main_block_impl_0 中增加了一个变量 a,在 block 中引用的变量 a 实际是在申明 block 时,被复制到main_block_impl_0 结构体中的那个变量 a。因为这样,我们就能理解,在 block 内部修改变量 a 的内容,不会影响外部的实际变量 a。
增加了下划线block后block实现方式发生了改变。
1.源码中增加一个名为 __Block_byref_i_0 的结构体,用来保存我们要 capture 并且修改的变量 i。
2.main_block_impl_0 中引用的是Block_byref_i_0 的结构体指针,这样就可以达到修改外部变量的作用。
NSConcreteMallocBlock
保存在堆中的 block,当引用计数为 0 时会被销毁。
NSConcreteMallocBlock 类型的 block 通常不会在源码中直接出现,因为默认它是当一个 block 被 copy 的时候,才会将这个 block 复制到堆中。以下是一个 block 被 copy 时的示例代码 (来自这里),可以看到,在第 8 步,目标的 block 类型被修改为 _NSConcreteMallocBlock。
变量的复制:
对于 block 外的变量引用,block 默认是将其复制到其数据结构中来实现访问的:
对于用 __block 修饰的外部变量引用,block 是复制其引用地址来实现访问的:
ARC 对 block 类型的影响
在 ARC 开启的情况下,将只会有 NSConcreteGlobalBlock 和 NSConcreteMallocBlock 类型的 block。