引言
接上篇文章003-OC对象原理探究 - isa 和 nonpointer,本文将通过实际代码演示,探究如何探究isa的走向,以及对象的继承关系。
###ISA走位探究
一、拿到ISA_MASK(isa掩码)
上期我们说道苹果对isa的优化,获取对象,是根据isa的mask来得到的,那么我们先把ISA_MASK取出

  1. __arm64__
  2. # define ISA_MASK 0x0000000ffffffff8ULL
  3. __x86_64__
  4. # define ISA_MASK 0x00007ffffffffff8ULL

ULL表示unsigned long long
二、代码实操
我们新建一个类QLDog,创建dog对象,打上断点,进入lldb调试模式
004--OC对象原理探究 - isa走位及对象继承链 - 图2
在控制台输入
1、p/x dog,得到dog对象的地址。(p/xlldb指令,请自行google搜索lldb常用指令学习)
004--OC对象原理探究 - isa走位及对象继承链 - 图3
2、接着输入x/4gx 0x00006000031385a0,得到dog的内存结构
004--OC对象原理探究 - isa走位及对象继承链 - 图4
3、此时猜想0x0000000109f35360是不是我们对象的isa?那么我们只需要与isa_mask做一次&即可
4、执行指令p/x 0x0000000109f35360 & 0x00007ffffffffff8,得到(long) $2 = 0x0000000109f35360,接着po 0x0000000109f35360可得到如下结果:004--OC对象原理探究 - isa走位及对象继承链 - 图5可见0x0000000109f35360为当前对象的isa
———-分割线———-
5、我们继续探索,继续调试x/4gx 0x0000000109f35360的内存结构如下:004--OC对象原理探究 - isa走位及对象继承链 - 图6
6、我们猜想,0x0000000109f35338是否也为0x0000000109f35360isa呢?我们重复与isa_mask&操作:004--OC对象原理探究 - isa走位及对象继承链 - 图7
7、很惊奇的发现,最终打印的也是QLDog。但是两个QLDog的地址不一样,分别是0x0000000109f353600x0000000109f35338,这是为什么呢?按照这个猜想,类对象在内存中是否可以无限开辟?也就是类对象是否是不只一个类。
#####验证
测试代码:

  1. Class cls1 = [QLDog class];
  2. Class cls2 = [QLDog alloc].class;
  3. Class cls3 = object_getClass([QLDog alloc]);
  4. Class cls4 = [QLDog alloc].class;
  5. NSLog(@"\n%p--\n%p--\n%p--\n%p--",cls1,cls2,cls3,cls4);

运行后,打印结果如下:004--OC对象原理探究 - isa走位及对象继承链 - 图8
打印结果的地址与dog对象一致,都是0x00006000031385a0,证明了我们前面的猜想:0x00006000031385a0为类QLDog,而0x0000000109f35338不是类。那它是什么东西?
接下来我借助一个工具004--OC对象原理探究 - isa走位及对象继承链 - 图9
来分析编译后的代码是什么样子的。
工程中,products文件夹内的可执行文件(.app或者macho)show in finder,找到可执行文件后,直接拖入MachOView工具中(.app要显示包内容,里面黑色的可执行文件就是)。
拖入MachOView后,找到Symbol table下的Symbols,搜索QLDog可看到我们的类:004--OC对象原理探究 - isa走位及对象继承链 - 图10
其中有几个value是系统生成的,我们这里只需关注_OBJC_METACLASS_$_QLDog即可。metaclass是元类的意思。由此结合上面的探索可知,我们探索对象dog的内存结构,得到对象的isa,&上isa_mask得到类QLDog,接着对其内存窥探,得到类的isa,接着&上isa_mask得到一个元类
到此为止,我们的isa探索走向为:对象isa—-类isa—-元类isa

我们重复以上的p/xx/4gx调试指令,最终得到004--OC对象原理探究 - isa走位及对象继承链 - 图11
我们对NSObject类的内存进行解析:004--OC对象原理探究 - isa走位及对象继承链 - 图12所得到的结果,与上图的最终结果一致。
由此可总结isa的走向:(请与继承链区分)
004--OC对象原理探究 - isa走位及对象继承链 - 图13
解释:
1、任何的对象的isa,会找到自己的类
2、自己的类的isa,会找到自己的类的元类
3、元类的isa,会找到根元类
4、根元类的isa最终找到自己

继承链探索
####对象的继承
设计代码如下:

  1. QLDog *dog = [QLDog alloc];
  2. Class dogSuperClass = [dog superclass];
  3. Class superClass1 = [dogSuperClass superclass];
  4. Class superClass2 = [superClass1 superclass];
  5. Class superClass3 = [superClass2 superclass];
  6. Class superClass4 = [superClass3 superclass];
  7. NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",dog,dog,dogSuperClass,dogSuperClass,superClass1,superClass1,superClass2,superClass2,superClass3,superClass3,superClass4,superClass4);

打印结果如下:
004--OC对象原理探究 - isa走位及对象继承链 - 图14
由此可得对象继承链为:dog——>person——>NSObject——>nil
####类的继承
设计代码如下:

  1. Class dogClass = [QLDog class];
  2. Class superClass5 = [dogClass superclass];
  3. Class superClass6 = [superClass5 superclass];
  4. Class superClass7 = [superClass6 superclass];
  5. Class superClass8 = [superClass7 superclass];
  6. Class superClass9 = [superClass8 superclass];
  7. NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",dogClass,dogClass,superClass5,superClass5,superClass6,superClass6,superClass7,superClass7,superClass8,superClass8,superClass9,superClass9);

打印结果如下
004--OC对象原理探究 - isa走位及对象继承链 - 图15
由此可得类继承链为:QLDog——>QLPerson——>NSObject——>nil
####元类的继承
设计代码如下:

  1. Class metaClass1 = object_getClass(dogClass);
  2. Class metaClass2 = class_getSuperclass(metaClass1);
  3. Class metaClass3 = class_getSuperclass(metaClass2);
  4. Class metaClass4 = class_getSuperclass(metaClass3);
  5. Class metaClass5 = class_getSuperclass(metaClass4);
  6. Class metaClass6 = class_getSuperclass(metaClass5);
  7. NSLog(@"\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p\n%@ -- %p",metaClass1,metaClass1,metaClass2,metaClass2,metaClass3,metaClass3,metaClass4,metaClass4,metaClass5,metaClass5,metaClass6,metaClass6);

打印结果如下:004--OC对象原理探究 - isa走位及对象继承链 - 图16

由此可得元类继承链为:QLDog——>QLPerson——>NSObject——>NSObject——>nil注意此处两个NSObject地址不一样。
####NSObject特殊情况
设计代码如下:

  1. //NSObject实例对象
  2. NSObject *object1 = [NSObject alloc];
  3. //NSObject类
  4. Class objClass = object_getClass(object1);
  5. //NSObject元类
  6. Class objMetaClass = object_getClass(objClass);
  7. //NSObject根元类
  8. Class rootMetaClass = object_getClass(objMetaClass);
  9. //NSObject根元类的根元类
  10. Class rootRootMetaClass = object_getClass(rootMetaClass);
  11. NSLog(@"\n%@--%p 实例对象 \n%@--%p 类 \n%@--%p 元类 \n%@--%p 根元类 \n%@--%p 根根元类 ",object1,object1,objClass,objClass,objMetaClass,objMetaClass,rootMetaClass,rootMetaClass,rootRootMetaClass,rootRootMetaClass);
  12. // NSObject根类获取父类
  13. Class objectSuperClass = class_getSuperclass(objClass);
  14. NSLog(@"%@---%p",objectSuperClass,objectSuperClass);
  15. // NSObject根元类获取父类
  16. Class objectSuperMetaClass = class_getSuperclass(objMetaClass);
  17. NSLog(@"%@---%p",objectSuperMetaClass,objectSuperMetaClass);

打印结果如下:
004--OC对象原理探究 - isa走位及对象继承链 - 图17
测试结果可得结论:
1、根类父类为nil
2、根元类父类为 NSObject类
3、所以万物皆来自NSObject
####继承图:箭头为superclass
004--OC对象原理探究 - isa走位及对象继承链 - 图18

总结
综合isa走位链以及类的继承链,我们引入苹果官方的isa/superclass链图
004--OC对象原理探究 - isa走位及对象继承链 - 图19

ps:我的疑问以及库某人解答如下:004--OC对象原理探究 - isa走位及对象继承链 - 图20

2021年06月21日16:09:39
——杭州