分类添加的方法可以“覆盖”原类方法
同名分类方法谁能生效取决于编译顺序,后编译先执行
名字相同的分类会引起编译报错

Category的实现原理

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

CategoryExtension区别

  1. Extension在编译器决议,他就是类的一部分,在编译期和头文件里的@interface以及实现文件里@implement一起用来隐藏类的私有信息,你必须有一个类才能为这个类添加Extension,所以你无法为系统的类比如NSString添加Extension 编译的时候,它的数据就已经包含在类信息中
  2. Category是在运行时,才会将数据合并到类信息中

+load方法

  • +load方法会在Runtime加载类、分类时调用
  • 每个类、分类的+load,在程序运行过程中只调用一次
  • 调用顺序

    • 先调用类的+load

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

      • 按照编译先后顺序调用(先编译,先调用)

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


runtime加载类、分类的时候调用
load方法可以继承,但是一般情况下不会主动调用load方法,都是让系统自动调用。

Category能否添加成员变量?如果可以,如何给Catogery添加成员变量?

不能直接给Category添加成员变量,但是可以间接实现Category有成员变量(Runtime关联对象)。分类中写属性,只会生成getset方法的声明,不会实现和生成一个成员变量。

默认情况下,因为分类地层结构的限制,不能添加成员变量到分类中,但是可以通过关联对象来间接实现

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

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

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

关联对象的原理

实现关联对象技术的核心对象有

  • AssociationsManager
  • AssociationsHashMap
  • ObjectAssociationMap
  • ObjcAssociation

关注源码

class AssociationsManager {
    static AssociationsHashMap *_map;
}
class AssociationsHashMap : public unordered_map<disguised_ptr_t, ObjectAssociationMap>
class ObjectAssociationMap : public std::map<void *, objcAssociation>
class ObjcAssociation {
    uintptr_t _policy;
    id _value;
}