iOS底层原理 - Category

167 阅读2分钟

底层原理 - Category

一、概述

Category是对类的扩展,可以添加一些常用方法,更加方便地调用;

二、Category的底层结构

定义在objc-runtime-new.h

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的加载处理过程

1、通过Runtime加载某个类的所有Category数据;

2、把所有Category的方法、属性、协议数据,合并到一个大数组中(顺序:后面参与编译的Category数据,会在数组的前面);

3、将合并后的分类数据(方法、属性、协议)插入到类原来的数据前面;

四、+load方法 和 +initialize方法

1、调用时机

1.1、load调用时间:

  • +load方法会在runtime加载类、分类时调用;
  • 每个类,分类的+load,在程序运行过程中只调用一次; 1.2、initialize调用时机:
  • +initialize方法会在类第一次接收到消息时调用;
  • 每个类中的Initialize仅会初始化一次;

2、调用方式

2.1、load调用方式:

  • load是根据函数地址直接调用; 2.2、initialize调用方式:
  • initialize是通过objc-msgSend调用;

3、调用顺序

3.1、load调用顺序:

3.1.1、先调用类的+load;

  • 按照编译先后顺序调用(先编译,先调用);
  • 调用子类的+load之前会调用父类的+load; 3.1.2、再调用分类的+load;
  • 按照编译先后顺序调用(先编译,先调用);

+load方法是根据方法地址直接调用,并不是经过objc_msgSend函数调用;

3.2、initialize调用顺序:

3.2.1、先调用父类的 +initialize方法;

3.2.2、再调用子类的 +initialize方法;

注意:在调用子类initialize时,若子类中没有,则会去父类中查找,这时有可能父类方法会出现多次调用的情况) 原文地址