分类添加的方法可以“覆盖”原类方法
同名分类方法谁能生效取决于编译顺序,后编译先执行
名字相同的分类会引起编译报错
Category
的实现原理
- 通过
Runtime
加载某个类的所有Category
数据 - 把所有
Category
的方法、属性、协议数据,合并到一个大数组中。后面参与编译的Category
数据,会在数组的前面。 - 将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面
Category
和Extension
区别
Extension
在编译器决议,他就是类的一部分,在编译期和头文件里的@interface
以及实现文件里@implement
一起用来隐藏类的私有信息,你必须有一个类才能为这个类添加Extension
,所以你无法为系统的类比如NSString
添加Extension
编译的时候,它的数据就已经包含在类信息中Category
是在运行时,才会将数据合并到类信息中
+load
方法
+load
方法会在Runtime
加载类、分类时调用- 每个类、分类的
+load
,在程序运行过程中只调用一次 调用顺序
先调用类的
+load
- 按照编译先后顺序调用(先编译,后调用)
- 调用子类的
+load
之前会先调用父类的+load
再调用分类的
+load
- 按照编译先后顺序调用(先编译,先调用)
Category
中有load
方法吗?load
方法是什么时候调用的?load
方法能继承吗?
有
在runtime
加载类、分类的时候调用load
方法可以继承,但是一般情况下不会主动调用load
方法,都是让系统自动调用。
Category
能否添加成员变量?如果可以,如何给Catogery
添加成员变量?
不能直接给Category
添加成员变量,但是可以间接实现Category
有成员变量(Runtime
关联对象)。分类中写属性,只会生成get
、set
方法的声明,不会实现和生成一个成员变量。
默认情况下,因为分类地层结构的限制,不能添加成员变量到分类中,但是可以通过关联对象来间接实现
// 添加关联对象
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;
}