Category 庖丁解牛版

一.Category的底层结构

在runtime运行中都是一个category_t的一个结构体,里面包含{
类名,
对象方法列表,
类方法列表,
协议,
实例化属性
}


Category的底层结.png

二.Category的加载处理过程

1.通过runtime加载某个类的所有Category的数据
2.把所有category的方法,属性,协议数据合并到一个大数组中(后面参与编译的category数据会在数组的前面)
3.将合并后的分类数据(方法,属性,协议),插入到类原来数据的前面

  • 导致:
    1.同样的方法有限调用分类的方法
    2.最后面参与编译的分类方法,优先调用

三.Category 和 Class extension(匿名分类/类扩展)的区别

1.Class Extension在编译的时候,它的数据就已经包含在类信息中
2.Category是在运行时,才会将数据合并到类信息中

四. +load 和 +initialize(匿名分类/类扩展)的区别

+load方法

1.会在runtime加载类,分类的时候调用
2.每个类,分类的+load,在程序运行过程中只调用一次
3.调用顺序:
1>先调用类的load 先编译的类优先调用load,调用子类的load之前,会先调用父类的load
2>在调用分类的load 先编译的分类,优先调用

+initialize方法
  1. 会在类第一次接受到消息的时候调用
  2. 会先调用父类的+initialize的方法,再调用子类的方法(每个类只会初始化一次)

区别:

  • 调用方式:
    load是根据函数地址直接调用
    initialize是通过objc_msgSend调用
  • 调用时刻:
    load是runtime加载类,分类的时候调用(只会调用一次)
    initialize是类第一次接收到消息时候会调用,每一个类只会initialize一次(父类的initialize可能会被调用多次)如果分类实现了+initialize就覆盖类本身的initialize调用

五.分类可以添加成员变量吗?

(添加之后只是声明了set和get方法,但是没有写成属性也没有实现set和get方法)
默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。但可以通过关联对象来间接实现

  • 关联对象提供了以下API

  • 添加关联对象
    void objc_setAssociatedObject(id object, const void * key,
    id value, objc_AssociationPolicy policy)

  • 获得关联对象
    id objc_getAssociatedObject(id object, const void * key)

  • 移除所有的关联对象
    void objc_removeAssociatedObjects(id object)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容