通过分析对象的本质得知实例对象的isa指向类对象,那类对象的isa呢,我们接下来就对 isa 的流程进行分析。
一、 lldb 探索isa
定义一个 SHPerson 对象,在 main 函数初始化并断点调试。
lldb打印结果如下:
- 第一次打印是
person的内存分布,并且0x000021a1000080e9(isa) & 0x0000000ffffffff8ULL,得到person的isa指向的内存地址为0x00000001000080e8且名为SHPerson的class对象。 - 第二次打印是class对象的内存分布,并且
0x00000001000080c0(isa) & 0x0000000ffffffff8ULL,得到的内存地址为0x00000001000080c0,po打印的结果是名为SHPerson的calss对象。 - 对比第一次第二次的打印,两个分别为
0x00000001000080e8和0x00000001000080c0的内存地址,打印的出来的class对象的名称是一样的。 - 第三次是打印
0x00000001000080c0的内存分布,并且0x00000001003790f0(isa) & 0x0000000ffffffff8ULL,得到的内存地址为0x00000001003790f0,po打印的结果是名为NSObject的calss对象。 - 再对比前两次的打印,发现是不一样的,
0x00000001003790f0和0x00000001000080e8、0x00000001000080c0打印出来的class对象名称是不一样的。 - 第四次是打印
0x00000001003790f0的内存分布,这次发现拿到的isa竟然和它一样本身一样,说明0x00000001003790f0的isa指向的是它自己本身。
接下来,将对这三个内存地址进行研究:
0x00000001000080e8
0x00000001000080c0
0x00000001003790f0
当然,这个内存地址是可能会变的,具体需要自己根据断点进行lldb打印。
二、烂苹果(MachOView)查看符号表,推导出类对象,元类对象,根元类对象。
使用MachOView打开代码的可执行文件(exec)。
找到符号表,并且滚动到黄褐色的部分。
发现,00000001000080E8,00000001000080C0的内存地址不就是上面提到要研究的么,再根据value这一列的值,就可以得知,0x00000001000080e8是类对象,0x00000001000080c0是元类对象,那么0x00000001003790f0是什么?0x00000001003790f0是一个叫根元类对象的东西。
总结如下:
实例对象的isa指向类对象,类对象的isa指向元类对象,元类对象的isa指向根元类对象,根元类对象的isa指向的是自己本身。
三、类对象,元类对象,根元类对象的继承链
类对象,元类对象,根元类对象是否也有继承链呢?如果有,是怎么样的一个继承链呢?添加一个继承至SHPerson的SHStudent类。
并且为了方便理解,下面暂时先把SHStudent比作子类(subClass),SHPerson比作父类(superClass),NSObject比作根类(rootClass)。
1. runtime部分API介绍。
导入 #import <objc/runtime.h>
object_getClass: 传一个对象,返回这个对象的类对象。class_getSuperclass: 传一个类,返回类的父类。objc_getClass: 传一个类名称,返回对应的类对象。objc_getMetaClass: 传一个类名称,返回对应的元类对象。
objc_getClass和objc_getMetaClass先作为了解,因为object_getClass就可以拿到类对象,元类对象,根元类对象,并且,更多runtime的API官方文档都有介绍。以下探索主要用到object_getClass和class_getSuperclass。
2. 使用 runtime API 打印输出
//1. 子类的instance对象isa流程和继承链。
NSLog(@"子类(SHStudent)打印");
SHStudent *student = [[SHStudent alloc] init];
// class对象
Class class_student = object_getClass(student);
// metaclass对象
Class metaclass_student = object_getClass(class_student);
// rootMetaclass对象
Class rootMetaclass_student = object_getClass(metaclass_student);
NSLog(@"class_student : %@ - %p",class_student, class_student);
NSLog(@"metaclass_student : %@ - %p",metaclass_student, metaclass_student);
NSLog(@"rootMetaclass_student: %@ - %p",rootMetaclass_student, rootMetaclass_student);
NSLog(@"------------------");
// class对象的superclass对象
Class superclass_student = class_getSuperclass(class_student);
// metaclass对象的superclass对象
Class superMetaclass_student = class_getSuperclass(metaclass_student);
// rootMetaclass对象的superclass对象
Class superRootMetaclass_student = class_getSuperclass(rootMetaclass_student);
NSLog(@"superclass_student : %@ - %p",superclass_student, superclass_student);
NSLog(@"superMetaclass_student : %@ - %p",superMetaclass_student, superMetaclass_student);
NSLog(@"superRootMetaclass_student: %@ - %p",superRootMetaclass_student, superRootMetaclass_student);
//2. 父类的instance对象isa流程和继承链。
NSLog(@"");
NSLog(@"父类(SHPerson)打印");
SHPerson *person = [[SHPerson alloc] init];
// class对象
Class class_person = object_getClass(person);
// metaclass对象
Class metaclass_person = object_getClass(class_person);
// rootMetaclass对象
Class rootMetaclass_person = object_getClass(metaclass_person);
NSLog(@"class_person : %@ - %p",class_person, class_person);
NSLog(@"metaclass_person : %@ - %p",metaclass_person, metaclass_person);
NSLog(@"rootMetaclass_person: %@ - %p",rootMetaclass_person, rootMetaclass_person);
NSLog(@"------------------");
// class对象的superclass对象
Class superclass_person = class_getSuperclass(class_person);
// metaclass对象的superclass对象
Class superMetaclass_person = class_getSuperclass(metaclass_person);
// rootMetaclass对象的superclass对象
Class superRootMetaclass_person = class_getSuperclass(rootMetaclass_person);
NSLog(@"superclass_person : %@ - %p",superclass_person, superclass_person);
NSLog(@"superMetaclass_person : %@ - %p",superMetaclass_person, superMetaclass_person);
NSLog(@"superRootMetaclass_person: %@ - %p",superRootMetaclass_person, superRootMetaclass_person);
//3. 根类的instance对象isa流程和继承链。
NSLog(@"");
NSLog(@"根类(NSObject)打印");
NSObject *object = [[NSObject alloc] init];
// class对象
Class class_object = object_getClass(object);
// metaclass对象
Class metaclass_object = object_getClass(class_object);
// rootMetaclass对象
Class rootMetaclass_object = object_getClass(metaclass_object);
NSLog(@"class_object : %@ - %p",class_object, class_object);
NSLog(@"metaclass_object : %@ - %p",metaclass_object, metaclass_object);
NSLog(@"rootMetaclass_object: %@ - %p",rootMetaclass_object, rootMetaclass_object);
NSLog(@"------------------");
// class对象的superclass对象
Class superclass_object = class_getSuperclass(class_object);
// metaclass对象的superclass对象
Class superMetaclass_object = class_getSuperclass(metaclass_object);
// rootMetaclass对象的superclass对象
Class superRootMetaclass_object = class_getSuperclass(rootMetaclass_object);
NSLog(@"superclass_object : %@ - %p",superclass_object, superclass_object);
NSLog(@"superMetaclass_object : %@ - %p",superMetaclass_object, superMetaclass_object);
NSLog(@"superRootMetaclass_object: %@ - %p",superRootMetaclass_object, superRootMetaclass_object);
3. lldb打印分析
红色箭头代表类对象的继承链,黄色箭头代表元类对象的继承链,绿色箭头代表根元类对象的继承链。
从图得知:
- 子类的类对象的父类,是父类的类对象,父类的类对象的父类,是根类的类对象,根类的类对象为nil。
- 子类的元类对象的父类,是父类的元类对象,父类的元类对象的父类,是根类的元类对象,根类的元类对象的父类,是根类的类对象。
结合下面的一张很经典的图,就更清楚了。
这种是一张广为流传并且很经典的图,这张图描述isa的流程以及class的继承链,通过以上的分析再来看这种图就有种豁然开朗的感觉,以前总看不懂这张。
其实不管是子类、父类、根类isa的流程和类的继承链都基本是一样的,真正的不同在于根元类对象(rootMetaclass)这个地方,isa的流程到这儿,isa指针再怎么指都是根元类对象自己,并且根元类对象的父类是根类,而根类对象的父类是一个nil。