方法列表(objc_method_list)结构
先了解方法结构
struct objc_method {
// 方法名称
SEL _Nonnull method_name OBJC2_UNAVAILABLE;
// 方法类型(编码格式 (类型c语言的字符串) (函数的类型:返回值类型 参数类型)
// ”v@:”意思就是这已是一个void类型的方法,没有参数传入。
// “i@:”就是说这是一个int类型的方法,没有参数传入。
// ”v@:@”意思就是这已是一个void类型的方法,有参数传入。
// */class_addMethod([self class], sel,@selector(testMethod),"v@:");
char * _Nullable method_types OBJC2_UNAVAILABLE;
// 法的实现 ———— 函数的入口(函数的指针 函数名 是啥都可以 不一定和sel相同)
IMP _Nonnull method_imp OBJC2_UNAVAILABLE;
}
方法列表结构
struct objc_method_list {
// 函数列表
struct objc_method_list * _Nullable obsolete OBJC2_UNAVAILABLE;
// 函数中的个数
int method_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
// 函数列表中的第一个函数地址
struct objc_method method_list[1] OBJC2_UNAVAILABLE;
}
分类是如何实现的?
category结构
typedef struct category_t {
// 类的名字
constchar *name;
// 类
classref_tcls;
// 所有给类添加的实例方法的列表
structmethod_list_t *instanceMethods;
// 所有添加的类方法的列表
structmethod_list_t *classMethods;
// 实现的所有协议的列表
structprotocol_list_t *protocols;
// 添加的所有属性}category_t;
structproperty_list_t *instanceProperties;
};
创建的分类(category)实际上是自定义的一个方法列表,这个分类列表被参入到类(class)的方法列表(objc_method_list)的结构中,如此一来,在外部调用的时候就能在方法列表中找到分类方法。
注:分类(category)中的实例方法、协议及属性 是添加到类上,而分类(category)的类方法和协议方法是添加到类的主类(meta class)上的。
分类为什么会"覆盖"掉原来的方法?
实际上如果分类(Category)和原来类都有相同的方法(testMethod),那么Category附加完成之后,类的方法列表里会有两个该方法(testMethod),而不是直接替换的。
Category的方法被放到了新方法列表的前面,而原来类的方法被放到了新方法列表的后面,这也就是我们平常所说的Category的方法会“覆盖”掉原来类的同名方法,这是因为RunTime在查找方法的时候是顺着方法列表的顺序查找的,它只要一找到对应名字的方法,就会停止。