美文网首页iOS开发技巧
OC底层原理04—类、元类、根元类 与 isa的关联

OC底层原理04—类、元类、根元类 与 isa的关联

作者: 夏天的枫_ | 来源:发表于2020-09-15 00:16 被阅读0次

    如题,今天来探究下类的一些信息,isa指针的指向就是该类对象的元类,每一个类都是它的元类的对象,元类是对类对象的描述。首先来分析一下代码

    //类对象内存存在个数为 1
    void lgTestClassNum(){
        Class class1 = [LGPerson class];
        Class class2 = [LGPerson alloc].class;
        Class class3 = object_getClass([LGPerson alloc]);
        Class class4 = [LGPerson alloc].class;
        NSLog(@"\n%p-\n%p-\n%p-\n%p",class1,class2,class3,class4);
    }
    
    void lgTestNSObject(){
        // NSObject实例对象
        NSObject *object1 = [NSObject alloc];
        // NSObject类
        Class class = object_getClass(object1);
        // NSObject元类
        Class metaClass = object_getClass(class);
        // NSObject根元类
        Class rootMetaClass = object_getClass(metaClass);
        // NSObject根根元类
        Class rootRootMetaClass = object_getClass(rootMetaClass);
        NSLog(@"\n%p 实例对象\n%p 类\n%p 元类\n%p 根元类\n%p 根根元类",object1,class,metaClass,rootMetaClass,rootRootMetaClass);
    }
    

    打印结果分析之:

    2020-09-14 23:24-isa分析[1763:92018] <LGPerson: 0x102055210>
    2020-09-14 23:24-isa分析[1763:92018] 
    0x100002588-
    0x100002588-
    0x100002588-
    0x100002588
    2020-09-14 23:24-isa分析[1763:92018] 
    0x1005135b0 实例对象
    0x7fffb1bd0140 类
    0x7fffb1bd00f0 元类
    0x7fffb1bd00f0 根元类
    0x7fffb1bd00f0 根根元类
    

    可以看到lgTestClassNum中打印的类对象地址都是同一个,说明:类对象存在个数仅有一份。在lgTestNSObject中实例对象地址与类的地址,以及元类、根元类、根根元类的地址是不一样的,其中元类、根元类、根根元类的地址则是一样的。这是为什么呢?
    在系列文章前几章中我们了解了isa的结构,类的首地址就是isa,isa中的shiftcls存储着类的一些信息,isa在类中存在这非常重要的关系,继续通过LLDB分析之。

    isa在类中用lldb分析
    isa指向:对象->类对象->元类对象->根元类对象,根元类对象的isa指向根元类自身
    元类可以存储类的自有信息,可供子类继承的类信息。
    实例对象没有继承关系,只有类与类间才有继承关系;
    根元类的父类为NSObject,NSObject 继承的地址没有,所以父类为nil。
    经典isa走位图
    实例对象的isa指向它的类对象Subclass,Subclass继承自它的父类Superclass,而Subclass的isa指向它的元类Subclass(meta),类和元类的地址是一样的。

    拓展:objc_class vs objc_object 关系?

    • 类的底层编码是—— objc_class
    • 对象的根对象—— objc_object
    • objc_class 又继承自 objc_object ,所有class也是对象——万物皆对象。
    • 所有的对象,类,元类都有isa。
      结构体类型objc_class 继承自objc_object类型,其中objc_object也是一个结构体,且有一个isa属性,所以objc_class也拥有了isa属性
      mian.cpp底层编译文件中,NSObject中的isa在底层是由Class 定义的,其中class的底层编码来自 objc_class类型,所以NSObject也拥有了isa属性
      NSObject 是一个类,用它初始化一个实例对象objc,objc 满足 objc_object 的特性(即有isa属性),主要是因为isa 是由 NSObject 从objc_class继承过来的,而objc_class继承自objc_object,objc_object 有isa属性。所以对象都有一个 isa,isa表示指向,来自于当前的objc_object
      objc_object(结构体) 是 当前的 根对象,所有的对象都有这样一个特性 objc_object,即拥有isa属性

    objc_object 和实例对象的关系?

    所有的对象都是继承NSObject,NSObject又继承自底层的objc_object(C/C++)结构体类型,底层的是没有对象而是结构体。

    类的内存 + 对象的内存

    class_data_bits_t
    先拓展:内存偏移

    • 常量地址,差4个字节,连续的地址存储,优化存储。
    • 对象的指针地址,&p 指针的指针,
    • 数组指针
      数组首个元素的指针地址作为数组的指针地址
      通过首地址的偏移,可挨个取出数组元素,偏移量则由元素类型的字节数决定。

    再来分析下类objc_object的结构信息

    // 注意new 、old版本差,此版本为objc4-781
    struct objc_class : objc_object {
        // Class ISA;  // 默认8字节
        Class superclass;  // 8字节
        cache_t cache;  // 8 + 4 + 2 + 2      // formerly cache pointer and vtable
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    
        /*篇幅有限,省略N多代码,主要代码分析上面即可*/
    };
    

    class_data_bits_t存储了类中的属性(property)、方法(method)、协议(protocol),这是类结构信息中的关键部分,通过之前的LLDB我们是可以获得类对象的首地址的,通过内存偏移的方式获取class_data_bits_t
    思路是:isa 8字节 + superClass 8字节 + cache_t(mask_t : 4 + buckerts : 8 + xxx :2 + xxx:2 = 16)。
    isa属性:继承自objc_object的isa,占 8字节
    superclass 属性:Class类型,Class是由objc_object定义的,是一个指针,占8字节
    cache属性:简单从类型class_data_bits_t目前无法得知,而class_data_bits_t是一个结构体类型,结构体的内存大小需要根据内部的属性来确定,而结构体指针才是8字节
    bits属性:只有首地址经过上面3个属性的内存大小总和的平移,才能获取到bits

    通过LLDB分析:


    获取ro_or_rw信息 打印propertylist

    781没有了propertylis, methodlist, protocllist. p $x 打印的是类型(刀x:是地址的别名)

    相关文章

      网友评论

        本文标题:OC底层原理04—类、元类、根元类 与 isa的关联

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