iOS isa与类关联的原理2

171 阅读3分钟

「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。

三 、继续探索isa_t是怎么做的,我们再次进入源码跳转到isa_t内部如下:

union isa_t { //联合体 isa_t
//两个初始化方法
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
 //一个Class
    Class cls;
//一个 bits 。 uintptr_t :在64位的机器上,intptr_t和uintptr_t分别是long int、unsigned long int的别名
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
// ISA_BITFIELD 这是一个宏 
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};

从union isa_t定义可以看出:

  • 提供了两个成员,cls 和 bits,由联合体的定义所知,这两个成员是互斥的,也就意味着,当初始化isa指针时,有两种初始化方式

    1. 通过cls初始化,bits无默认值
    2. 通过bits初始化,cls有默认值
  • 还提供了一个结构体定义的位域,用于存储类信息及其他信息,结构体的成员ISA_BITFIELD,这是一个宏定义,有两个版本 arm64(对应ios 移动端) 和 x86_64(对应macOS),以下是它们的一些宏定义,如下图所示:

image.png

注:

  • nonpointer有两个值,表示自定义的类等,占1位
    0:纯isa指针
    1:不只是类对象地址,isa中包含了类信息、对象的引用计数等
  • has_assoc表示关联对象标志位,占1位
    0:没有关联对象
    1:存在关联对象
  • has_cxx_dtor 表示该对象是否有C++/OC的析构器(类似于dealloc),占1位如果有析构函数,则需要做析构逻辑
    如果没有,则可以更快的释放对象, 析构函数 类似于 oc层面的 dealloc;
  • shiftclx表示存储类的指针的值(类的地址), 即类信息arm64中占 33位,开启指针优化的情况下,在arm64架构中有33位用来存储类指针x86_64中占 44位;
  • magic 用于调试器判断当前对象是真的对象 还是 没有初始化的空间,占6位;
  • weakly_refrenced是 指对象是否被指向 或者 曾经指向一个ARC的弱变量, 没有弱引用的对象可以更快释放deallocating 标志对象是是否正在释放内存;
  • has_sidetable_rc表示 当对象引用计数大于10时,则需要借用该变量存储进位;
  • extra_rc(额外的引用计数) --- 表示该对象的引用计数值,实际上是引用计数值减1, 如果对象的引用计数为10,那么extra_rc为9;

针对两种不同平台,其isa的存储情况如图所示

image.png

我们lldb 调试 可以看到经过一系列赋值 将HJPerson类信息存进了shiftcls中

image.png

注:
为什么在shiftcls赋值时(newisa.shiftcls = (uintptr_t)cls >> 3)需要类型强转?

因为内存的存储不能存储字符串,机器码只能识别 0 、1这两种数字,所以需要将其转换为uintptr_t数据类型,这样shiftcls中存储的类信息才能被机器码理解, 其中uintptr_t是long。

至此,我们得出结论:在isa初始化obj->initInstanceIsa(cls, hasCxxDtor)的时候,通过isa_t联合体,在位域运算中,将类信息cls存进了存储类的指针的值shiftclx , 最后isa = newisa;isa中既有HJPerson的指针,又有HJPerson的信息。就这样isa与类关联到一起了。

四 、拓展 验证 isa 与 类 的关联

简单点 我们在x86_64中通过isa & ISA_MSAK验证\

image.png 流程:

  • 1.在_class_createInstanceFromZone方法,此时cls 与isa已经关联完成,执行po objc
  • 2.执行x/4gx obj,得到isa指针的地址0x001d8001000021fd
  • 3.将isa指针地址 & ISA_MASK(处于macOS,使用x86_64中的宏定义),即 po 0x001d8001000021fd & 0x00007ffffffffff8,得出HJPerson.x86_64中,ISA_MASK 宏定义的值为0x00007ffffffffff8ULL

image.png