美文网首页iOS 底层原理 iOS 进阶之路
OC底层原理:对象、类、isa 逻辑梳理

OC底层原理:对象、类、isa 逻辑梳理

作者: markhetao | 来源:发表于2020-09-15 14:12 被阅读0次

    OC底层原理 学习大纲

    我们已经从底层熟悉了对象isa。但碎片化的知识让我有点头晕。 学着学着发现,我不知道如何用语言来完整的描述他们了。

    为了避免造成邯郸学步的惨剧。

    现在,我将以上帝视角来梳理一下他们之间的关系。

    在了解之前,如果你还不了解isa结构类的原理。请先去了解一下。
    👉 isa结构
    👉 类的原理

    如果你准备好了,我们就开始吧~

    前期准备

    main.m文件中加入测试代码

    • HTTeacher继承自HTPersonHTPerson继承自NSObject
    • teacherHTTeacher实例化对象
    @interface HTPerson : NSObject
    @end
    
    @implementation HTPerson
    @end
    
    @interface HTTeacher: HTPerson
    @end
    
    @implementation HTTeacher
    @end
    
    int main(int argc, const char * argv[]) {
        
        @autoreleasepool {
            
            HTTeacher * teacher = [[HTTeacher alloc]init];
    
            NSLog(@"%p", teacher);
        }
        return 0;
    }
    

    NSLog位置加入断点

    objc4 源码

    objc4 源码下载-> objc4-781.tar.gz

    objc_object

    obj4源码中搜索struct objc_object:

    image.png

    这是对象在底层的实现模板。首元素是isa(这里涉及到struct结构的内存优化,我们这里记住结论。isaobjc_object的首位元素即可)

    相关知识: 内存优化

    objc_class

    obj4源码中搜索struct objc_class:

    image.png

    从上图知道,在类的内存中,首地址表示isasuperclassisa后面,需要内存地址偏移8位获取。

    梳理逻辑

    image.png

    探索路径:

    1. 从对象开始探索

    teacher对象

    • 打印地址:p/x teacher
    • 获取isa指针: x/g $0
    • 从isa指针中取出类地址: p/x 0x001d8001000021c9 >> 3 << 20 >> 17
    • 打印类: po 0x00000001000021c8
    image.png

    成功找到继承类HTTeacher

    2 寻找父类源头:

    查看上面准备的objc_class结构,父类首地址是isa指针,占用了8字节。

    • 所以我们从类地址偏移8位就可以找到superclass类。
    • 找到superclass地址: p/x 0x00000001000021c8 + 8
    • 获取父类的isa指针: x/g 0x00000001000021d0
    • 从isa指针中取出类地址: p/x 0x0000000100002178 >> 3 << 20 >> 17
    • 打印父类: po 0x0000000100002178
    image.png

    成功找到HTTeacher的父类HTPerson

    为了一探究竟。我们一口气追根溯源,往上层层找寻父类
    • 寻找superclass地址:p/x 0x0000000100002178 + 8
    • 获取父类的isa指针: x/g 0x0000000100002180
    • 从isa指针中取出类地址: p/x 0x0000000100333140 >> 3 << 20 >> 17
    • 打印父类:po 0x0000000100333140
    image.png

    成功找到HTPerson的父类NSObject

    再接再厉,往上溯源
    • 寻找superclass地址: p/x 0x0000000100333140 + 8
    • 获取父类的isa指针: x/g 0x0000000100333148
    • 从isa指针中取出类地址: p/x 0x0000000000000000 >> 3 << 20 >> 17
    • 打印父类:po 0x0000000000000000
    image.png

    NSObjet 的父类是nil(0x0000000000000000)。 到达尽头!

    所以我们说OC中,想要确定类的继承关系,找到NSObject就可以停止了。因为已经到尽头了!

    附上完整截图:


    类的继承

    3. 寻找isa的源头:

    isa相比于类而言,不需要进行偏移。但是需要准确找到类中isa的地址

    查看上面准备的objc_class结构,父类首地址是isa指针。

    • 我们应该用x/g打印获取isa的准确内存位置
    • 从isa中获取类的地址,我们需要准确截取shiftcls部分。
      (我一般使用 内存地址>>3 << 20 >> 17, 你们也可以&与上ISA_MASK 0x00007ffffffffff8ULL
    • 获取类的isa指针 x/g 0x00000001000021c8
    • 从Isa指针中取出类地址: p/x 0x00000001000021a0 >> 3 << 20 >> 17
    • 打印类名: po 0x00000001000021a0
    image.png

    成功找到HTTeacher元类

    • HTTeacher类地址是:0x00000001000021c8
    • HTTeacher元类地址是:0x00000001000021a0

    我们接着往下。打印过程都一样。这里直接上完整打印图:

    isa指向图

    我们发现2个情况:

    1. HTTeacher的isa首先指向HTTeacher的元类,之后直接指向了NSObject元类。与HTTeacher的父类HTPerson完全无关
    2. NSObject元类的isa指针指向的是NSObject元类

    1. 如何确定是NSObject元类,而不是NSObjet自身类?

    image.png
    我们打印NSObject自身类NSObject元类地址
    • 与上面地址0x00000001003330f0进行对比。 可以肯定上面打印的是NSObject元类地址

    2. NSObject元类也是类,那它有父类(superclass)吗?

    image.png
    • 通过指针偏移8位,到达superclass地址。
    • 打印发现NSObject元类有父类,它的父类指向了NSObject本类

    3. NSObject元类有父类, 那其他元类(比如HTTeacher元类)有父类吗?

    image.png

    曾经的我以为打印不出来,那就是其他元类都没有父类咯?

    聪明的你看出错误了吗😂

    image.png

    总结:

      1. 对象内的isa指针指向自己的类.
      1. 有完整的继承关系(每个类都通过superclass记录自己的父类,层层溯源)
      1. 根类NSObject
        NSObject的父类为nil,所以NSObject无父类
        所有类的最终父类都是NSObject
      1. isa的指向与类的继承无关
      1. 任何类isa都是先指向自己元类,再指向NSObject元类
        (除了NSObject类, 因为他自己元类就是NSObject元类)
      1. 根元类NSObject元类
        NSObject元类isa指向永远都是自己
      1. 元类也有父类,根元类(NSObject元类)的父类(superclass)是NSObject类

    奉上经典的isa指向类的继承关系图

    isa和类继承流程图.png

    再奉上我的备注图:


    isa和类继承流程图.png

    欢迎一起交流学习。

    相关文章

      网友评论

        本文标题:OC底层原理:对象、类、isa 逻辑梳理

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