1.Category定义
Category的主要作用是为已经存在的类添加方法。 Objective-C 中的 Category 就是对装饰模式的一种具体实现。它的主要作用是在不改变原有类的前提下,动态地给这个类添加一些方法。
2.使用场景
- 可以按照功能分组,放到不同的分类里,使类结构更清晰
- 降低耦合性,同一个类可以有多个开发人员进行开发
- 模拟多继承
- 声明私有方法
- 分解体积庞大的类文件
- 把静态库的私有方法公开
- 模拟多继承(另外可以模拟多继承的还有protocol)
3.特点
- 1.分类是用于给原有类添加方法的,因为分类的结构体指针中,没有属性列表,只有方法列表。
原则上讲它只能添加方法, 不能添加属性(成员变量),实际上可以通过其它方式添加属性 ?; - 2.分类中的可以写@property, 但不会生成
setter/getter 方法, 也不会生成实现以及私有的成员变量,会编译通过,但是引用变量会报错; - 3.如果分类中有和原有类同名的方法, 会优先调用分类中的方法, 就是说会忽略原有类的方法,同名方法调用的优先级为?
分类 > 本类 > 父类 ; - 4.如果多个分类中都有和原有类中同名的方法, 那么调用该方法的时候执行谁由编译器决定;编译器会执行最后一个参与编译的分类中的方法。
- 5.运行时决议
- 6.同名分类方法生效取决于编译顺序
- 7.名字相同的分类会引起编译报错
- 8.运行时决议
4.原理
一个类的类对象只有一个,存储着实例方法,元类对象也只有一个,存储着类方法 实例方法的调用轨迹是实例对象通过isa指针找到类对象,在类对象的方法列表中查找该方法,如果找不到,就通过superclass指针继续向上查找 类方法的调用轨迹是类对象通过isa指针找到元类对象,在元类对象的方法列表中查找该方法,如果找不到,就通过superclass指针继续向上查找
(1)分类的实例方法是被加载到类对象中,分类的类方法也是被加载到元类对象中
(2)编译时,分类是被编译成_category_t结构体,_category_t结构体存储着分类的实例方法列表、类方法列表、协议、属性。 分类实例方法、类方法不是在编译时,加载到类对象、元类对象中
在.cpp文件中可以导出这个结论
static struct _category_t _OBJC_$_CATEGORY_Person_$_Test __attribute__ ((used, section ("__DATA,__objc_const"))) =
{
"Person",
0, // &OBJC_CLASS_$_Person,
(const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Test,
(const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_Person_$_Test,
0,
0,
};
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[1];
} _OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Test __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"run", "v16@0:8", (void *)_I_Person_Test_run}}
};
static struct /*_method_list_t*/ {
unsigned int entsize; // sizeof(struct _objc_method)
unsigned int method_count;
struct _objc_method method_list[1];
} _OBJC_$_CATEGORY_CLASS_METHODS_Person_$_Test __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"test", "v16@0:8", (void *)_C_Person_Test_test}}
};
struct _category_t {
const char *name;
struct _class_t *cls;
const struct _method_list_t *instance_methods;
const struct _method_list_t *class_methods;
const struct _protocol_list_t *protocols;
const struct _prop_list_t *properties;
};
(3)分类的数据是通过runtime动态加载到类信息中(类对象、元类对象中)
Category编译之后的底层结构是struct category_t,里面存储着分类的对象方法、类方法、属性、协议信息 在程序运行的时候,runtime会将Category的数据,合并到类信息中(类对象、元类对象中)
|