方法列表(objc_method_list)結(jié)構(gòu)
先了解方法結(jié)構(gòu)
struct objc_method {
// 方法名稱
SEL _Nonnull method_name OBJC2_UNAVAILABLE;
// 方法類型(編碼格式 (類型c語言的字符串) (函數(shù)的類型:返回值類型 參數(shù)類型)
// ”v@:”意思就是這已是一個void類型的方法,沒有參數(shù)傳入。
// “i@:”就是說這是一個int類型的方法,沒有參數(shù)傳入。
// ”v@:@”意思就是這已是一個void類型的方法,有參數(shù)傳入。
// */class_addMethod([self class], sel,@selector(testMethod),"v@:");
char * _Nullable method_types OBJC2_UNAVAILABLE;
// 法的實現(xiàn) ———— 函數(shù)的入口(函數(shù)的指針 函數(shù)名 是啥都可以 不一定和sel相同)
IMP _Nonnull method_imp OBJC2_UNAVAILABLE;
}
方法列表結(jié)構(gòu)
struct objc_method_list {
// 函數(shù)列表
struct objc_method_list * _Nullable obsolete OBJC2_UNAVAILABLE;
// 函數(shù)中的個數(shù)
int method_count OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space OBJC2_UNAVAILABLE;
#endif
// 函數(shù)列表中的第一個函數(shù)地址
struct objc_method method_list[1] OBJC2_UNAVAILABLE;
}
分類是如何實現(xiàn)的?
category結(jié)構(gòu)
typedef struct category_t {
// 類的名字
constchar *name;
// 類
classref_tcls;
// 所有給類添加的實例方法的列表
structmethod_list_t *instanceMethods;
// 所有添加的類方法的列表
structmethod_list_t *classMethods;
// 實現(xiàn)的所有協(xié)議的列表
structprotocol_list_t *protocols;
// 添加的所有屬性}category_t;
structproperty_list_t *instanceProperties;
};
創(chuàng)建的分類(category)實際上是自定義的一個方法列表,這個分類列表被參入到類(class)的方法列表(objc_method_list)的結(jié)構(gòu)中,如此一來,在外部調(diào)用的時候就能在方法列表中找到分類方法。
注:分類(category)中的實例方法、協(xié)議及屬性 是添加到類上,而分類(category)的類方法和協(xié)議方法是添加到類的主類(meta class)上的。
分類為什么會"覆蓋"掉原來的方法?
實際上如果分類(Category)和原來類都有相同的方法(testMethod),那么Category附加完成之后,類的方法列表里會有兩個該方法(testMethod),而不是直接替換的。
Category的方法被放到了新方法列表的前面,而原來類的方法被放到了新方法列表的后面,這也就是我們平常所說的Category的方法會“覆蓋”掉原來類的同名方法,這是因為RunTime在查找方法的時候是順著方法列表的順序查找的,它只要一找到對應名字的方法,就會停止。