感谢《objc category的秘密》的作者,本文章是站在巨人的肩膀上。
category主要用来为一个已有的类添加方法(实例方法和类方法均可),为了实现这个功能,要通过编译器和runtime的配合。
编译器的工作
在runtime的源码可以看到,catagory的定义为:
struct objc_category {
char * _Nonnull category_name OBJC2_UNAVAILABLE;
char * _Nonnull class_name OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable instance_methods OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable class_methods OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
}
可以看到可以在catagory中添加实例方法、类方法和协议,但是不能添加实例变量。
注意:
- 可以用
objc_setAssociatedObject
和objc_getAssociatedObject
方法在分类中添加实例变量,不过这种方法生成的与一个普通的实例变量完全是两码事。- 可以在catagory里面实现协议,但是少见。
一个类可能会有多个分类,在编译阶段,编译器会把这些分类生成一个数组,存储着所有分类的方法。
runtime的工作
一个类的+ load
方法被调用时,表示这个类的所有方法都已经加载完毕(包括所有分类方法),在这之前,runtime会将编译阶段的到的分类方法插入到这个类里面。
方法会前序添加进类的方法数组中,也就是说如果原来类的方法是a,b,c,catagory的方法是1,2,3,那么插入之后的方法将会是1,2,3,a,b,c,也就是说,原来类的方法被category的方法覆盖了,但被覆盖的方法确实还在那里。
网友评论