美文网首页
五、isa走位 和 类结构分析

五、isa走位 和 类结构分析

作者: KB_MORE | 来源:发表于2020-09-09 10:21 被阅读0次

    先附上经典图, 表示敬畏😸


    看了好多遍的isa走位图
    isa的走位
    1. 实例对象(Instance of Subclass)的isa 指向 类(class)

    2. 类对象(class) isa 指向 元类(Meta class)

    3. 元类(Meta class)的isa 指向 根元类(Root metal class

    4. 元类(Root metal class)isa 指向它自己本身,形成闭环,这里的根元类就是NSObject

    superclass(继承关系)走位
    1. 类(subClass) 继承自 父类(superClass)

    2. 父类(superClass) 继承自 根类(RootClass ),此时的 根类是指 NSObject

    3. 根类 继承自 nil,所以 根类NSObject可以理解为万物起源

    4. 子类元类(metal SubClass) 继承自 父类元类(metal SuperClass)

    5. 父类元类(metal SuperClass ) 继承自 根元类(Root metal Class

    6. 根元类(Root metal Class) 继承于 根类(Root class ),此时的 根类是指 NSObject

    • 【注意】 实例对象之间 没有 继承关系,之间有继承关系 *

    分析

    LGPerson

    @interface LGPerson : NSObject
    + (void)sayHello;
    - (void)say666;
    @end
    #import "LGPerson.h"
    
    @interface LGPerson ()
    @property (nonatomic, copy) NSString *name;
    @end
    @implementation LGPerson{
        NSString *_hobby;
    }
    + (void)sayHello{
        NSLog(@"sayHello");
    }
    - (void)say666{
        NSLog(@"say666");
    }
    @end
    
    

    LGTeacher 继承LGPerson

    #import "LGPerson.h"
    
    @interface LGTeacher : LGPerson
    
    @end
    
    #import "LGTeacher.h"
    
    @implementation LGTeacher
    
    @end
    
    
            LGPerson *person = [LGPerson alloc];
            LGTeacher  *teacher = [LGTeacher alloc];
    
            NSLog(@"Hello, Person!  %@",person);
            NSLog(@"Hello, Teacher!  %@",teacher);
    
    图片.png
    图片.png

    p/x : 打印person首地址
    x/4gx :查看person内存情况: 第一个为isa指针地址
    指针地址 & 0x00007ffffffffff8ULL: 获取类信息
    isa走位
    person -> LGPerson ->LGPerson(元类)->NSObject(根元类)->NSObject

    类结构分析

    LGPerson继承至NSObject

    @interface NSObject <NSObject> {
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wobjc-interface-ivars"
        Class isa  OBJC_ISA_AVAILABILITY;
    #pragma clang diagnostic pop
    }
    

    NSObject的底层编译是NSObject_IMPL结构体,
    其中 Classisa指针的类型,是由objc_class定义的类型,
    objc_class是一个结构体。在iOS中,所有的Class都是以 objc_class为模板创建的`

    struct NSObject_IMPL {
        Class isa;
    };
    typedef struct objc_class *Class;
    

    查看源码已经被废除

    图片.png
    不过可以根据最后一行注释(/* Use Class instead of struct objc_class * */
    )找到目前所用的class 图片.png 同理可查出 objc_class的父类objc_object 图片.png

    【问题】objc_class 与 objc_object 有什么关系?

    通过上述的源码查找以及main.cpp中底层编译源码,有以下几点说明:

    • 结构体类型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 是由 NSObjectobjc_class继承过来的,而objc_class继承自objc_objectobjc_objectisa属性。所以对象都有一个 isa,isa表示指向,来自于当前的objc_object

    • objc_object(结构体) 是 当前的 根对象所有的对象都有这样一个特性 objc_object,即拥有isa属性

    【百度面试题】objc_object 与 对象的关系

    • 所有的对象 都是以 objc_object为模板继承过来的

    • 所有的对象 是 来自 NSObject(OC) ,但是真正到底层的 是一个objc_object(C/C++)的结构体类型

    【总结】 objc_object对象关系继承关系

    总结

    • 所有的对象 + + 元类 都有isa属性

    • 所有的对象都是由objc_object继承来的

    • 简单概括就是万物皆对象,万物皆来源于objc_object,有以下两点结论:

      • 所有以 objc_object为模板 创建的对象,都有isa属性

      • 所有以objc_class为模板,创建的,都有isa属性

    • 在结构层面可以通俗的理解为上层OC底层对接

      • 下层是通过 结构体 定义的 模板,例如objc_class、objc_object
      • 上层 是通过底层的模板创建的 一些类型,例如CJLPerson

    objc_class、objc_object、isa、object、NSObject等的整体的关系,如下图所示

    image

    到底类中有哪些信息呢?

    根据前文提及的objc_class 的新版定义(objc4-781版本)如下,有以下几个属性

    struct objc_class : objc_object {
        // Class ISA; //8字节
        Class superclass; //Class 类型 8字节
        cache_t cache;             // formerly cache pointer and vtable
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
        
        //....方法部分省略,未贴出
    }
    

    可以通过地址偏移获取bits里面的类信息, 首先我们还需要知道地址的偏移量

    • isa: objc继承至objc_object, 所以也包含一个isa指针,继承自objc_object的isa,占 8字节

    • superclass 属性:Class类型,Class是由objc_object定义的,是一个指针,占8字节

    • cache属性:简单从类型class_data_bits_t目前无法得知,而class_data_bits_t是一个结构体类型,结构体的内存大小需要根据内部的属性来确定,而结构体指针才是8字节

    • bits属性:只有首地址经过上面3个属性的内存大小总和的平移,才能获取到bits

    struct cache_t {
    #if CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_OUTLINED
        explicit_atomic<struct bucket_t *> _buckets; // 是一个结构体指针类型,占8字节
        explicit_atomic<mask_t> _mask; //是mask_t 类型,而 mask_t 是 unsigned int 的别名,占4字节
    #elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
        explicit_atomic<uintptr_t> _maskAndBuckets; //是指针,占8字节
        mask_t _mask_unused; //是mask_t 类型,而 mask_t 是 uint32_t 类型定义的别名,占4字节
        
    #if __LP64__
        uint16_t _flags;  //是uint16_t类型,uint16_t是 unsigned short 的别名,占 2个字节
    #endif
        uint16_t _occupied; //是uint16_t类型,uint16_t是 unsigned short 的别名,占 2个字节
    
    

    获取bits

    所以有上述计算可知,想要获取bits的中的内容,只需通过类的首地址平移32字节即可

    以下是通过lldb命令调试的过程


    图片.png

    也可以打印属性列表


    图片.png

    以及存在ro里面的ivars


    图片.png class_rw_t中的一部分重要信息 图片.png

    相关文章

      网友评论

          本文标题:五、isa走位 和 类结构分析

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