美文网首页
004--OC对象原理探究 - isa走位及对象继承链

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

作者: Mr_wick | 来源:发表于2021-06-21 16:11 被阅读0次

    引言

    接上篇文章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走位及对象继承链

          本文链接:https://www.haomeiwen.com/subject/upcyyltx.html