Objective-C Class Ivar Layout 探索

539 查看

这次探索源于一个朋友问的问题,当我们定义一个类的实例变量的时候,可以指定其修饰符:

这使得 ivar (instance variable) 可以像属性一样在 ARC 下进行正确的引用计数管理。
那么问题来了,假如这个类是动态生成的:

该如何像上面一样来添加 ivar 的属性修饰符呢?
刨根问底了一下,发现 ivar 的修饰信息存放在了 Class 的 Ivar Layout 中:

ivarLayout 和 weakIvarLayout 分别记录了哪些 ivar 是 strong 或是 weak,都未记录的就是基本类型和 __unsafe_unretained 的对象类型。

这两个值可以通过 runtime 提供的几个 API 来访问:

但我们几乎没可能用到这几个 API,IvarLayout 的值由 runtime 确定,没必要关心它的存在,但为了解决上述问题,我们试着破解了 IvarLayout 的编码方式。

举个例子说明,若类定义为:

则储存 strong ivar 的 ivarLayout 的值为 0x012000
储存 weak ivar 的 weakIvarLayout 的值为 0x1200

一个 uint8_t 在 16 进制下是两位,所以编码的值每两位一对儿,以上面的 ivarLayout 为例:

  1. 前两位 01 表示有 0 个非 strong 对象和 1 个 strong 对象
  2. 之后两位 20 表示有 2 个非 strong 对象和 0 个 strong 对象
  3. 最后两位 00 为结束符,就像 cstring 的  一样

同理,上面的 weakIvarLayout:

  1. 前两位 12 表示有 1 个非 weak 对象和接下来连续 2 个 weak 对象
  2. 00 结束符

这样,用两个 layout 编码值就可以排查出一个 ivar 是属于 strong 还是 weak 的,若都没有找到,就说明这个对象是 unsafe_unretained.

做个练习,若类定义为: