
这篇没啥新的点, 主要是对已知的 isa 流程敲些代码做验证
isa 具体是啥看这里: 其他: Tagged pointer 与 isa
isa 做了什么看这里: 三. runtime 的消息机制 - 作为全局查找索引的 isa
下面这张图很常见(出自苹果官方文档)

这里我用下面的代码, 验证以上的过程:
NSObjectTest.zip
准备工作
- 后面要注意区分指针本身的地址和指针指向的地址, 这是两基础概念, 但容易弄混
- 指针的地址:
&obj - 指针的值\指针指向的地址:
obj,&*obj - 指针所指向的地址, 所存的值:
*obj - 结构体的字段, 在其内部是按顺序分配的内存. 在输出结构体值时, 第一个字段如果刚好 8 字节, 其值就存放在指向结构体的指针所指向的地址
- 我们知道
struct objc_object {isa_t isa}只有一个字段, isa, 并且 isa_t 刚好就是 8 个字节 其他: Tagged pointer 与 isa - 所以一个对象 objc, 是一个
struct objc_object *(二. runtime 怎么实现封装), 其所指向的地址的前八个字节存的就是isa - 其中 llvm 可以利用以下指令查看地址: 其他: 探究源码中的小工具
所以我们看下面的源码:
NSObject *obj = [[NSObject alloc] init];
printf("\n ------------------------ 准备工作 ----------------------------\n");
printf(" obj 是啥: [obj.description UTF8String] = %s\n",[obj.description UTF8String]);
printf(" obj 地址: &obj = %p\n",&obj);
printf(" obj 的值(指向的地址): obj = %p\n",obj);
printf(" *obj 的地址 (等同于 obj指向的地址) : &*obj = %p\n",&*(void **)(__bridge void*)obj);
printf(" *obj 的值(obj指向的地址, 所存的值): *obj = %p\n",*(void **)(__bridge void*)obj);
printf(" 结论是, obj 第一个字段, 是个指向%p 的指针, 这个指针,指向 %p",&*(void **)(__bridge void*)obj, *(void **)(__bridge void*)obj);
探究过程
class: obj.isa 与 [objc class] 都指向其对象的类
- 先打出一个对象指针指向的地址的值, 然后再打出 objc.class 指向的地址
- 根据以前了解的 Tagged piointer(其他: Tagged pointer 与 isa) 将第一个值
& ISA_MASK - 得出结论,
obj.isa与objc.class的指向一直//0x1dffff9730c119 printf(" obj.isa = %p\n",*(void **)(__bridge void*)obj); //0x7fff9730c118 printf(" obj.class (指向的地址) = %p\n",obj.class); //0x7fff9730c118 printf(" obj.isa & ISA_MASK = %p\n",(void *)(objc_isa & 0x00007ffffffffff8ULL));
metaclass: objc.isa.isa *obj.class
- 还是最前面的理论,
*obj.class指向等同于objc.class.isa等同于obj.isa.isa - 上面的地址, 都为
metaclass的地址
没办法显式的找到可以显示 metaclass 的函数, 如果无法验证, 所以最终只能验证后面metaclas 指向自己void * objClass = (void *)(objc_isa & 0x00007ffffffffff8ULL); unsigned long long int obj_isa_isa = *(unsigned long long int *)objClass; //*obj.class = 0x7fff9730c0f0 printf(" *obj.class = %p\n",*(void **)(__bridge void*)obj.class); //objc.isa.isa = 0x7fff9730c0f0 printf(" obj.isa.isa = %p\n",(void *)obj_isa_isa); //objc.isa.isa == *obj.class printf(" obj.isa.isa == *obj.class \n");
RootMetaClass 最终指向 RootMetaClass 自己
上面拿到了 objc.class.isa 根据理论, 他就是 metaclass 的地址, 所以我们只需要验证这个metaClass最终指向的是自己, 那么上面图中,最上面一环就做完了验证
void * objMetaClass = (void *)(obj_isa_isa & 0x00007ffffffffff8ULL);
unsigned long long int obj_isa_isa_isa = *(unsigned long long int *)objMetaClass;
// 0x7fff9730c0f0
printf(" obj_isa_isa_isa & ISA_MASK = %p\n",obj_isa_isa_isa);
// 0x7fff9730c0f0
printf(" obj_isa_isa_isa & ISA_MASK = %p\n",(void *)(obj_isa_isa_isa & 0x00007ffffffffff8ULL));
整个流程比较绕, 具体代码中有很多注释, 执行插断点边打印着看会更清晰