深入理解Block之Block的类型

iOS-Source-Code-Analyse 首发
Follow: sunbohong· Github

深入理解Block之Block的类型

当我在 2012 年刚刚开始从事 iOS 开发工作时,对 Block 的使用开始逐渐在 iOS 开发者中推广开来(Block 的第一个稳定 ABI 版本是在 Mac OS X 10.6 被引入的。)。作为 iOS 开发中非常吸引我的一个特性,对其的深入分析自然必不可少。

重要声明:虽然我已经仔细的检查了自己的相关代码和相关的措辞,但是请不要盲目相信本文的正确性。我已经见过非常多的经验开发者对于 Block 有错误的理解(我也不会例外)。请一定保持一颗怀疑的心。

类型简介

对 block 稍微有所了解的人都知道,block 会在编译过程中,会被当做结构体进行处理。 其结构Block-ABI-Apple大概是这样的:

isa 指针会指向 block 所属的类型,用于帮助运行时系统进行处理。

Block 常见的类型有三种,分别是 _NSConcreteStackBlock _NSConcreteMallocBlock _NSConcreteGlobalBlock

另外还包括只在GC环境下使用的 _NSConcreteFinalizingBlock _NSConcreteAutoBlock _NSConcreteWeakBlockVariable

下面摘自 libclosure-65 – Block_private.h-213

_NSConcreteGlobalBlock & _NSConcreteStackBlock

_NSConcreteGlobalBlock & _NSConcreteStackBlock 是 block 初始化时设置的类型(上文中 Block-ABI-Apple 已经提及,并且 CGBlocks_8cpp_source.html#l00141 也提到过)。

在以下情况中,block 会初始化为 _NSConcreteGlobalBlock

_NSConcreteMallocBlock

在非垃圾收集环境下,当 _NSConcreteStackBlock 类型的block 被真正复制时,在 _Block_copy_internal 方法内部,会转换为 _NSConcreteMallocBlock libclosure-65/runtime.c

_NSConcreteFinalizingBlock&_NSConcreteAutoBlock

在垃圾收集环境下,当 block 被复制时,如果block 有 ctors & dtors 时,则会转换为 _NSConcreteFinalizingBlock 类型,反之,则会转换为 _NSConcreteAutoBlock 类型

_NSConcreteWeakBlockVariable

GC环境下,当对象被 __weak __block 修饰,且从栈复制到堆时,block 会被标记为 _NSConcreteWeakBlockVariable 类型。

ARC环境的特殊处理

下面的代码均通过添加 objc_retainBlock _Block_copy_Block_copy_internal 符号断点进行测试

  • 在 ARC 下,block 类型通过=进行传递时,会导致调用objc_retainBlock->_Block_copy->_Block_copy_internal方法链。并导致 __NSStackBlock__ 类型的 block 转换为 __NSMallocBlock__ 类型。


objc4-680/runtime/NSObject.mm-193
提及到了这一点。

测试代码:

日志:

  • 在 ARC 下,不同的属性修饰符以及不同赋值、取值方式均会对方法调用产生影响。下表为测试结果。
\ STRONG RETAIN COPY
直接赋值 _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal
间接赋值 _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal
通过属性取值 _Block_copy->_Block_copy_internal-> _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal-> _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal-> _Block_copy->_Block_copy_internal _Block_copy->_Block_copy_internal-> _Block_copy->_Block_copy_internal
通过变量取值

直接赋值:

间接赋值:

通过属性取值

通过变量取值

测试代码:

日志:

1 3 收藏 评论

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部