004--OC对象原理探究 - isa走位及对象继承链

引言

接上篇文章003-OC对象原理探究 - isa 和 nonpointer,本文将通过实际代码演示,探究如何探究isa的走向,以及对象的继承关系。

ISA走位探究

一、拿到ISA_MASK(isa掩码)
上期我们说道苹果对isa的优化,获取对象,是根据isa的mask来得到的,那么我们先把ISA_MASK取出

__arm64__
#     define ISA_MASK        0x0000000ffffffff8ULL
__x86_64__
#     define ISA_MASK        0x00007ffffffffff8ULL

ULL表示unsigned long long
二、代码实操
我们新建一个类QLDog,创建dog对象,打上断点,进入lldb调试模式

image.png

在控制台输入
1、p/x dog,得到dog对象的地址。(p/xlldb指令,请自行google搜索lldb常用指令学习)
image.png

2、接着输入x/4gx 0x00006000031385a0,得到dog的内存结构
image.png

3、此时猜想0x0000000109f35360是不是我们对象的isa?那么我们只需要与isa_mask做一次&即可
4、执行指令p/x 0x0000000109f35360 & 0x00007ffffffffff8,得到(long) $2 = 0x0000000109f35360,接着po 0x0000000109f35360可得到如下结果:
image.png
可见0x0000000109f35360为当前对象的isa
-------分割线-------
5、我们继续探索,继续调试x/4gx 0x0000000109f35360的内存结构如下:
image.png

6、我们猜想,0x0000000109f35338是否也为0x0000000109f35360isa呢?我们重复与isa_mask&操作:
image.png

7、很惊奇的发现,最终打印的也是QLDog。但是两个QLDog的地址不一样,分别是0x0000000109f353600x0000000109f35338,这是为什么呢?按照这个猜想,类对象在内存中是否可以无限开辟?也就是类对象是否是不只一个类。

验证

测试代码:

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

运行后,打印结果如下:

image.png

打印结果的地址与dog对象一致,都是0x00006000031385a0,证明了我们前面的猜想:0x00006000031385a0为类QLDog,而0x0000000109f35338不是类。那它是什么东西?
接下来我借助一个工具
image.png

来分析编译后的代码是什么样子的。
工程中,products文件夹内的可执行文件(.app或者macho)show in finder,找到可执行文件后,直接拖入MachOView工具中(.app要显示包内容,里面黑色的可执行文件就是)。
拖入MachOView后,找到Symbol table下的Symbols,搜索QLDog可看到我们的类:
image.png

其中有几个value是系统生成的,我们这里只需关注_OBJC_METACLASS_$_QLDog即可。metaclass是元类的意思。由此结合上面的探索可知,我们探索对象dog的内存结构,得到对象的isa,&上isa_mask得到类QLDog,接着对其内存窥探,得到类的isa,接着&上isa_mask得到一个元类
到此为止,我们的isa探索走向为:对象isa---类isa---元类isa

我们重复以上的p/xx/4gx调试指令,最终得到

image.png

我们对NSObject类的内存进行解析:
image.png
所得到的结果,与上图的最终结果一致。
由此可总结isa的走向:(请与继承链区分)
image.png

解释:
1、任何的对象的isa,会找到自己的类
2、自己的类的isa,会找到自己的类的元类
3、元类的isa,会找到根元类
4、根元类的isa最终找到自己

继承链探索

对象的继承

设计代码如下:

QLDog *dog = [QLDog alloc];
Class dogSuperClass = [dog superclass];
Class superClass1 = [dogSuperClass superclass];
Class superClass2 = [superClass1 superclass];
Class superClass3 = [superClass2 superclass];
Class superClass4 = [superClass3 superclass];
    
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);

打印结果如下:

image.png

由此可得对象继承链为:dog——>person——>NSObject——>nil

类的继承

设计代码如下:

    Class dogClass    = [QLDog class];
    Class superClass5 = [dogClass superclass];
    Class superClass6 = [superClass5 superclass];
    Class superClass7 = [superClass6 superclass];
    Class superClass8 = [superClass7 superclass];
    Class superClass9 = [superClass8 superclass];
    
    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);

打印结果如下

image.png

由此可得类继承链为:QLDog——>QLPerson——>NSObject——>nil

元类的继承

设计代码如下:

    Class metaClass1 = object_getClass(dogClass);
    Class metaClass2 = class_getSuperclass(metaClass1);
    Class metaClass3 = class_getSuperclass(metaClass2);
    Class metaClass4 = class_getSuperclass(metaClass3);
    Class metaClass5 = class_getSuperclass(metaClass4);
    Class metaClass6 = class_getSuperclass(metaClass5);
    
    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);

打印结果如下:
image.png

由此可得元类继承链为:QLDog——>QLPerson——>NSObject——>NSObject——>nil注意此处两个NSObject地址不一样。

NSObject特殊情况

设计代码如下:

    //NSObject实例对象
    NSObject *object1 = [NSObject alloc];
    //NSObject类
    Class objClass = object_getClass(object1);
    //NSObject元类
    Class objMetaClass = object_getClass(objClass);
    //NSObject根元类
    Class rootMetaClass = object_getClass(objMetaClass);
    //NSObject根元类的根元类
    Class rootRootMetaClass = object_getClass(rootMetaClass);
    
    NSLog(@"\n%@--%p 实例对象 \n%@--%p 类 \n%@--%p 元类 \n%@--%p 根元类 \n%@--%p 根根元类 ",object1,object1,objClass,objClass,objMetaClass,objMetaClass,rootMetaClass,rootMetaClass,rootRootMetaClass,rootRootMetaClass);


    // NSObject根类获取父类
    Class objectSuperClass = class_getSuperclass(objClass);
    NSLog(@"%@---%p",objectSuperClass,objectSuperClass);
    
    // NSObject根元类获取父类
    Class objectSuperMetaClass = class_getSuperclass(objMetaClass);
    NSLog(@"%@---%p",objectSuperMetaClass,objectSuperMetaClass);

打印结果如下:

image.png

测试结果可得结论:
1、根类父类为nil
2、根元类父类为 NSObject类
3、所以万物皆来自NSObject

继承图:箭头为superclass

image.png

总结

综合isa走位链以及类的继承链,我们引入苹果官方的isa/superclass链图


image.png

ps:我的疑问以及库某人解答如下:
image.png

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

你可能感兴趣的:(004--OC对象原理探究 - isa走位及对象继承链)