Skip to content

objc_class

ShenYj edited this page Mar 8, 2022 · 9 revisions

objc_class

objc_class的内存分布:

objc_class

.

  • isa:继承自objc_object的isa,占8字节
  • superclass:objc_class类型的一个结构体指针,占8字节
  • cache:方法缓存、获取占16字节
  • bits:可以指向class_rw_t和class_ro_t,可以通过首地址平移32字节获取(isa + superclass + cache => 8 + 8 + 16)
    • class_rw_t:运行时生成,包含class_ro_t。插入分类的方法、协议、属性,不能添加成员变量,可读可写
    • class_ro_t:编译期生成的,只读的,它存储了当前类在编译期就已经确定的属性、方法以及协议,它里面是没有分类中定义的方法和协议 ( 这里面的list 都是一维数组)

Class

Class类型其实就是指向objc_class(objc-runtime-new.h) 结构体的指针

/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class;

objc_class继承自objc_object, 结构体里存储了父类、方法列表等信息

struct objc_class : objc_object {
    // Class ISA;
    Class superclass;
    cache_t cache;             // formerly cache pointer and vtable
    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

    class_rw_t *data() const {
        return bits.data();
    }

    考虑篇幅等原因,其他静态成员变量、方法省略...
}

.

  • 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;                  // 4字节
        #elif CACHE_MASK_STORAGE == CACHE_MASK_STORAGE_HIGH_16
        explicit_atomic<uintptr_t> _maskAndBuckets;
        mask_t _mask_unused;
    
        explicit_atomic<uintptr_t> _maskAndBuckets;
        mask_t _mask_unused;
    
        #if __LP64__
        uint16_t _flags;    // 2字节
        #endif
        uint16_t _occupied; // 2字节
    
        考虑篇幅等原因,其他静态成员变量、方法省略...
    }

    cache_t的主要成员

    • _bucketsstruct bucket_t *类型的一个结构体指针
    • _maskmask_t类型, 在64位下为4字节
    • _flagsuint16_t类型, 2字节
    • _occupieduint16_t类型, 2字节

cache_t 通过散列表来缓存曾经调用过的方法,可以提高方法的查找速度 (这里指的就是 msg_send 的快速查找)

class_data_bits

通过objc_class中的定义, 相当于为btis提供了一个get方法, 其返回值类型为class_rw_t

class_rw_t *data() const {
    return bits.data();
}

bits.data()源码

class_rw_t* data() const {
    return (class_rw_t *)(bits & FAST_DATA_MASK);
}

将bits与FAST_DATA_MASK进行位运算,只取其中的3, 47位转换成class_rw_t*返回

class_rw_t

class_rw_t的内存结构

class_rw_t

class_rw_t源码

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint16_t witness;
#if SUPPORT_INDEXED_ISA
    uint16_t index;
#endif

    explicit_atomic<uintptr_t> ro_or_rw_ext;

    Class firstSubclass;
    Class nextSiblingClass;

    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};
        }
    }

    ...
}

从源码中,我们可以知道class_rw_t是一个结构体,存储了方法列表,属性列表,协议列表等等。

class_ro_t

class_ro_t的内存结构

class_ro_t

  • class_rw_t是在运行时生成的,它在realizeClass中生成,它包含了class_ro_t。 它在_objc_init方法中关于dyld的回调的map_images中最终将分类的方法与协议都插入到自己的方法列表、协议列表中。
    它不包含成员变量列表,因为成员变量列表是在编译期就确定好的,它只保存在class_ro_t中。不过class_rw_t中包含了一个指向class_ro_t的指针。

  • class_ro_t存放的是编译期间就确定的;而class_rw_t是在runtime时才确定,它会先将class_ro_t的内容拷贝过去,然后再将当前类的分类的这些属性、方法等拷贝到其中。所以可以说class_rw_tclass_ro_t的超集,当然实际访问类的方法、属性等也都是访问的class_rw_t中的内容

  • class_rw_t中的property_list中只有属性,没有成员变量

    • 通过{}定义的成员变量,会存储在类的bits属性中,通过bits -> data() ->ro() -> ivars获取成员变量列表,除了包括成员变量,还包括属性定义的成员变量
    • 通过@property定义的属性,也会存储在bits属性中,通过bits -> data() -> properties() -> list获取属性列表,其中只包含属性
  • 类中的方法列表除了包括实例方法,还包括属性的set方法get方法, 还有系统在底层添加了一个c++的.cxx_destruct方法

外链

Getting Started

Social

Clone this wiki locally