文章目录
写的有些乱…
分类
Category分类是Objective-C 2.0添加的语言特性,主要作用是为已经存在的类添加方法。Category可以做到在既不子类化,也不侵入一个类的源码的情况下,为原有的类添加新的方法,从而实现扩展一个类或者分离一个类的目的。
通常Category有以下几种使用场景
- 把类的不同实现方法分开到不同的文件里
- 可以由多个开发者共同完成一个类
- 声明私有方法
- 模拟多继承
- 将framework私有方法公开化
分类的结构
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; //属性
};
将新建的分类的.m文件,转为c++,就可以看到 上面分类的底层结构,_category_t结构体
_category_t结构体定义了一个结构体变量
变量名有些长 _OBJC_$_CATEGORY_Person_$_Test
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,
(const struct _protocol_list_t *)&_OBJC_CATEGORY_PROTOCOLS_$_Person_$_Test,
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_Person_$_Test,
};
后面是对_category_t结构体类型变量_category_t OBJCKaTeX parse error: Expected group after '_' at position 17: …CATEGORY_Person_̲_Test的赋值。
对比分类结构体的定义
- 第一个成员,“Person”,分类所属的类名
- 第二个,都设为0
- 第三个成员,
(const struct _method_list_t *)&_OBJC_$_ CATEGORY_INSTANCE_METHODS_Person_$_Test
这个也是一个结构体变量,存储着实例方法,如图
实例方法test的实现
- 第四个成员,
(const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_Person_$_Test
也是一个结构体变量,存储着类方法,如图
类方法test1的实现
在分类中,如果实现了对象方法、类方法,都会添加到对应的方法列表结构体中。
但如果仅仅定义、没有实现,就不会加进来 - 第五个成员,
(const struct _protocol_list_t *)&_OBJC_CATEGORY_PROTOCOLS_$_Person_$_Test
协议相关的结构体变量,Test分类中我遵循了NSCopying协议
这个结构体中包含了一个_protocol_t结构体数组
_protocol_t的定义如下
_OBJC_PROTOCOL_NSCopying的赋值如下
- 第六个成员,
(const struct _prop_list_t *)&_OBJC_$_PROP_LIST_Person_$_Test
属性相关的结构体变量,Test分类中,写了一个NSString类型的变量str
当类中有一个方法,多个分类中有相同的方法,调用这个方法一定执行的是分类中的方法,具体是哪一个分类就要看编译时的顺序,在attachCategories方法中 对分类列表进行倒序遍历 将分类包含的方法列表、协议列表、属性列表分别合并到对应的大数组中,将合并好的分类数据插入到类原来的数据前面。
对分类列表的遍历是倒序,即最后参与编译的分类先被添加到方法列表的开始位置。
attachCategories(Class cls, category_list *cats, bool flush_caches)
方法实现中
日志中eat先编译,打印是eat的方法????
上面那个应该不准 哈哈哈哈
控制编译顺序