美文网首页
OC底层05:类结构分析

OC底层05:类结构分析

作者: 木扬音 | 来源:发表于2020-09-20 15:20 被阅读0次

    在谈及面向对象编程的时候,总是离不开 对象对象 是对客观事物的抽象, 是对 对象 的抽象。它们的关系是,对象 的实例,对象 的模板。
    在OC中对象的信息存储在中,那么是以什么样的结果存在的呢,我们可以在objc的源码中找到下面代码,从中可以发现objc_class 是继承objc_object 的,也就是说 也是一个对象。这也是OC中万物皆对象的由来。因其继承自 objc_object ,自然默认就含有了 objc_object 的成员 isa

    isa和继承

    image.png

    我们可以通过isa流程和继承关系图发现

    isa的走向有以下几点说明:

    • 实例对象(Instance of Subclass)的 isa 指向类(class)

    • 类对象(class) isa 指向元类(Meta class)

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

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

    superclass(即继承关系)的走向也有以下几点说明:

    • 之间 的继承关系:

      • 子类(subClass) 继承自 父类(superClass)

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

      • 根类 继承自nil,所以根类即NSObject可以理解为万物起源,即无中生有

    • 元类也存在继承,元类之间的继承关系如下:

      • 子类的元类(metal SubClass) 继承自 父类的元类(metal SuperClass)

      • 父类的元类(metal SuperClass) 继承自 根元类(Root metal Class)

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

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

    /// Represents an instance of a class.
    struct objc_object {
        Class _Nonnull isa  OBJC_ISA_AVAILABILITY;
    };
    struct objc_class : objc_object {
        // Class ISA;//8字节
        Class superclass; //8字节
        cache_t cache; //8字节            // formerly cache pointer and vtable
        class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
    }
    
    • isa:关于isa的在[OC底层04:isa和类的关联],(https://www.jianshu.com/p/ad042414e5e4)可以找到答案,继承自objc_objectisa,占8字节
    • superclass:指向父类,依旧是Class类型,所以也占8字节
    • cache: 方法缓存列表,存储了最近调用的方法
    • bitsclass_data_bits_t类型,存储详细的类信息
      objc_class、objc_object、isa、object、NSObject

    cache_t

    我们进入cache_t,发现主要有如下几个属性

    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个字节
    

    通过计算cache_t中属性大小为16字节
    所以我们可以通过获取的首地址,通过平移32字节来获取bits中的内容

    获取bits

    准备工作

    定义一个继承自NSObject的类YPPerson

    @interface YPPerson : NSObject
    {
        NSString *hobby;
    }
    @property (nonatomic, copy) NSString *yp_name;
    - (void)sayHello;
    + (void)sayBye;
    @end
    
    @implementation YPPerson
    - (void)sayHello{
    }
    
    + (void)sayBye{
    }
    @end
    

    通过lldb调试打印bits信息

    image.png

    获取属性列表

    class_data_bits_t方法class_rw_t,点进去class_rw_t中提供获取了属性列表、方法列表等方法

      const method_array_t methods() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>()->methods;
            } else {
                return method_array_t{v.get<const class_ro_t *>()->baseMethods()};
            }
        }
    
        const property_array_t properties() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>()->properties;
            } else {
                return property_array_t{v.get<const class_ro_t *>()->baseProperties};
            }
        }
    
        const protocol_array_t protocols() const {
            auto v = get_ro_or_rwe();
            if (v.is<class_rw_ext_t *>()) {
                return v.get<class_rw_ext_t *>()->protocols;
            } else {
                return protocol_array_t{v.get<const class_ro_t *>()->baseProtocols};
            }
        }
    

    所以我们在刚刚获取到的bits信息基础上,通过class_rw_t提供的方法,我们可以继续打印出属性列表

    获取属性列表
    • p $3.properties()命令中的propertoes方法是由class_rw_t提供的,方法中返回的实际类型为property_array_t(数组)

    • 由于list的类型是property_list_t,是一个指针,所以通过p *$5获取内存中的信息,同时也证明bits中存储了property_list,即属性列表

    • p $6.get(1),获取YPPerson中的成员变量, 发现会报错,提示数组越界了,说明 property_list 中只有一个属性yp_name

    获取方法列表

    image.png
    • 通过 p $4.methods()获得具体的方法列表的list结构,其中methods也是class_rw_t提供的方法

    • 通过打印的count = 4可知,存储了4个方法,可以通过p $7.get(i)内存偏移的方式获取单个方法,i 的范围是0-3

    • 如果在打印 p $7.get(4),获取第五个方法,也会报错,提示数组越界

    相关文章

      网友评论

          本文标题:OC底层05:类结构分析

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