iOS进阶专项分析(四)、类的结构

直接开搞,打开objc源码, 搜索Class, 发现Class实质上是结构体objc_class的重定义, 换句话说类的本质就是结构体。继续深入,找到object_class结构体的定义部分:(objc_objectid类型的, 所以这里就找到底了)

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() { 
        return bits.data();
    }
    void setData(class_rw_t *newData) {
        bits.setData(newData);
    }
    
    ...
    
}

这里我们可以看出类的结构中主要包含isasuperclasscachebits以及一个bits.data, 可以看出类的数据都存在bits.data属性中,继续研究这个属性,发现这个属性是class_rw_t类型的,我们继续查看class_rw_t的结构,

struct class_rw_t {
    // Be warned that Symbolication knows the layout of this structure.
    uint32_t flags;
    uint32_t version;

    const class_ro_t *ro; //只读文件

    method_array_t methods; //方法
    property_array_t properties;//属性
    protocol_array_t protocols;//协议

    Class firstSubclass;
    Class nextSiblingClass;

    char *demangledName;
    
    ...
    
}

发现这里面存的有方法methods,属性properties,协议protocols,还有一个类型为class_ro_t的文件,注意这个文件是用const进行修饰的,也就是说这个文件是不可以进行更改,是一个只读的文件!我们继续查看这个类型class_ro_t的结构,发现了这个文件里面主要包含下面这些成员变量

struct class_ro_t {
    uint32_t flags;
    uint32_t instanceStart;
    uint32_t instanceSize;
#ifdef __LP64__
    uint32_t reserved;
#endif

    const uint8_t * ivarLayout;
    
    const char * name;
    method_list_t * baseMethodList; //基础方法列表
    protocol_list_t * baseProtocols; //基础协议列表
    const ivar_list_t * ivars;  //属性成员变量 

    const uint8_t * weakIvarLayout;
    property_list_t *baseProperties;

    method_list_t *baseMethods() const {
        return baseMethodList;
    }
};

到这里,按照源码一层层深入,类的结构已经大致查看完了,思维导图总结如下:

iOS进阶专项分析(四)、类的结构_第1张图片
OC类的结构.png

看完类的结构,我们需要注意一个细节:

class_ro_t类里面的属性成员变量ivars是用const修饰的!也就是说,在类的结构中,ivars这个属性是不可更改的,如果使用Runtime的API注册和实现一个类,必须注意添加成员变量的顺序

    //1、自定义一个类
    Class BMClass = objc_allocateClassPair([NSObject class], @"BMClass", 0);
    //2、给类添加一个成员变量ivar
    NSString * name = @"name";
    class_addIvar(BMClass, name.UTF8String, sizeof(id), log2(sizeof(id)), @encode(id));
    //3、注册这个类
    objc_registerClassPair(BMClass);

添加成员变量class_addIvar操作必须要在类的注册objc_registerClassPair之前,如果类已经注册完毕之后,ivar就添加不进去了!会导致你获取这个成员变量获取不到!这也是一个常见的知识坑点

溪浣双鲤的技术摸爬滚打之路

你可能感兴趣的:(iOS进阶专项分析(四)、类的结构)