交換類主動(dòng)調(diào)用+(void)load方法
我們的MethodSwizzled在+(void)load方法中執(zhí)行交換操作后,如果在其他地方在主動(dòng)調(diào)用一次的話那么之前交換過的方法又會(huì)被交換回去,效果就等于是沒有交換。
解決的方案就是使用單利設(shè)計(jì)模式,保證方法交換的代碼只被執(zhí)行一次口蝠。
交換的方法是父類的方法
如果交換的方法是父類的方法,就會(huì)導(dǎo)致父類調(diào)用該方法時(shí)報(bào)錯(cuò),因?yàn)楦割悰]有子類中的那個(gè)被交換的方法多糠。
解決方案:
- 先嘗試給自己添加要交換的方法。
- 然后再將父類的IMP給swizzle浩考。
+ (void)lg_betterMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
if (!cls) NSLog(@"傳入的交換類不能為空");
Method oriMethod = class_getInstanceMethod(cls, oriSEL);
Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
// 嘗試添加
BOOL success = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(oriMethod));
if (success) {// 添加成功了證明自己沒有夹孔,那么直接替換
class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
} else { // 自己有直接交換
method_exchangeImplementations(oriMethod, swiMethod);
}
}
交換的方法不存在
如果要交換的方法不存在,那么就會(huì)導(dǎo)致交換失敗析孽,那么這時(shí)候我們需要在上面的基礎(chǔ)上多增加一次判斷搭伤,判斷在執(zhí)行方法交換之前。
+ (void)lg_bestMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
if (!cls) NSLog(@"傳入的交換類不能為空");
Method oriMethod = class_getInstanceMethod(cls, oriSEL);
Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
if (!oriMethod) {
class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
method_setImplementation(swiMethod, imp_implementationWithBlock(^(id self, SEL _cmd){ }));
}
BOOL didAddMethod = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
if (didAddMethod) {
class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
} else {
method_exchangeImplementations(oriMethod, swiMethod);
}
}