OC中Category分析

分类的底层结构

struct category_t {
    const char *name;
    classref_t cls;
    struct method_list_t *instanceMethods; // 对象方法
    struct method_list_t *classMethods; // 类方法
    struct protocol_list_t *protocols; // 协议
    struct property_list_t *instanceProperties; // 属性
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
};

实现原理

将方法、属性、协议数据保存在category_t的结构体中,然后将结构体中的方法列表拷贝到类对象的方法列表中

为什么不能添加成员变量

Category中可以添加属性,但不会帮我们生成成员变量,只会生成get、set方法的声明,需要我们手动去实现。因为category_t的结构体里面是不存在成员变量的。成员变量是保存在实例对象中的,成员变量的查找是通过地址偏移,而对应的偏移是在编译的那一刻就已经确定好的,而category是在运行时。因此我们就无法在运行时将Category中的成员变量添加到实例对象的结构体中。

Category中有load方法吗?是什么时候调用的?能继承吗?

有;程序启动装载类信息的时候调用的;能继承,但是在调用子类的load方法之前,会先调用父类的load方法。

load&initialize的区别,以及它们在Category重写时的调用次序。

load:
调用方式:通过load方法的内存地址直接调用load方法
调用时刻:runtime加载类、分类的时候调用,只会调用一次
调用顺序:调用load之前会先调用父类的load方法,分类中的load方法不会覆盖本类的load方法,先编译的分类优先调用load方法。

initialize:
调用方式:通过objc_msgSend调用
调用时刻:类第一次接收到消息的时候调用,类的initialize只会调用一次,父类的initialize可能会调用多次
调用顺序:initialize先初始化父类再初始化子类,如果子类没有实现initialize,会调用父类的initialize,所以父类的initialize可能会被多次调用,如果分类实现了initialize,就覆盖类本身的initialize。

你可能感兴趣的:(OC中Category分析)