Category的同名方法覆蓋并不是真的其他同名方法就消失了哈街,而是因?yàn)橄到y(tǒng)調(diào)用方法的時(shí)候根據(jù)方法名在method_list中查找方法留瞳,找 到第一個(gè)名字匹配的方法之后就不繼續(xù)往下找了。所以每次調(diào)用的都是method_list中最前面的同名方法骚秦。實(shí)際其他同名方法還在 method_list中。
所以我們可以根據(jù)selector查找到所有的同名method璧微,然后調(diào)用
static inline void __invoke_all_method(id self, SEL selecotr)
{
//1. 根據(jù)self作箍,獲取class Class class = object_getClass(self);
//2. 獲取方法列表 uint count; Method *methodList = class_copyMethodList(class, &count);
//3. 遍歷方法列表 for (int i = 0; i < count; i++)
{
Method method = methodList[i];
//4. 根據(jù)SEL查找方法
if (!sel_isEqual(selecotr, method_getName(method)))
{ continue; }
//5. 獲取方法的實(shí)現(xiàn)
IMP implement = method_getImplementation(method);
//6. 直接調(diào)用方法的實(shí)現(xiàn)
((void(*)(id,SEL))implement)(self, selecotr);
}
}
+ (void)invokeAllClassMethodWithSelector:(SEL)selector
{
__invoke_all_method(self, selector);
}
根據(jù)剛剛介紹的原理,我們封裝了一個(gè)通過(guò)selector調(diào)用所有同名method的方法前硫。
- 根據(jù)self胞得,獲取class,如果self是實(shí)例方法的self屹电,這里獲取的是普通的class阶剑,如果self是類方法的self,這里獲取的是metaClass危号。實(shí)例方法存放在普通class中牧愁,類方法存放在metaClass中。了解更多請(qǐng)看iOS開發(fā)RunTime之函數(shù)調(diào)用
- 通過(guò)class_copyMethodList獲取class的方法列表外莲。如果class傳的是metaClass猪半,獲取的是類方法的方法列表,如果class是普通class偷线,獲取的是實(shí)例方法的方法列表磨确。
- 遍歷methodList
- 根據(jù)SEL查找method
- 獲取IMP
- 直接調(diào)用IMP
在系統(tǒng)的+initialize中,我們用invokeAllClassMethodWithSelector調(diào)用自定義 的+categoryInitialize声邦。這時(shí)候乏奥,在category的+categoryInitialize中添加屬性,就不怕Category覆蓋了亥曹。