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。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容