前言
runtime 的黑魔法很多人都一定聽過,或者已經在使用了。但是,怎麼swizzle方法才是最好呢?
一般寫法
Method originalMethod = class_getInstanceMethod(aClass, originalSel);
Method swizzleMethod = class_getInstanceMethod(aClass, swizzleSel);
method_exchangeImplementations(originalMethod, swizzleMethod);
或者是下面這種方式,swizzle第二種寫法:
Method originalMethod = class_getInstanceMethod(aClass, originalSel);
Method swizzleMethod = class_getInstanceMethod(aClass, swizzleSel);
BOOL didAddMethod = class_addMethod(aClass, originalSel, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
if (didAddMethod) {
class_replaceMethod(aClass, swizzleSel, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
}else{
method_exchangeImplementations(originalMethod, swizzleMethod);
}
更好寫法
其它,這樣寫,一般不會有問題,但是在一些情況下,比如這個hook的類沒有實作你要swizzle的方法,這時是沒有swizzle成功的,然後你自己寫的 swizzle 裡又自己調用自己,就無限循環。
Method originalInsMethod = class_getInstanceMethod(class, originalSelector);
// 處理為執行個體方法
if (originalInsMethod)
{
method_exchangeImplementations(originalInsMethod, swizzledMethod);
}else{
// 處理為類方法
Method originalClassMethod = class_getClassMethod(class, originalSelector);
if (originalClassMethod)
{
method_exchangeImplementations(originalClassMethod, swizzledMethod);
}else{
// 如果hook的類沒有實作這個方法,則先添加方法,然後設定方法的IMP為一個空block。否則直接class_replaceMethod,則方法實則沒有交接
class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
method_setImplementation(swizzledMethod, imp_implementationWithBlock(^(id self, SEL _cmd){}));
}
}
總結
至于這個為什麼會更好? 有時間在慢慢說啦~
參考
- 利用ios的hook機制實作adobe air ios ane下appdelegate的動态替換 - CSDN部落格
- Method結構, SEL, IMP了解 - Vanbein's Blog
- 深入了解 Objective-C 的方法調用流程 - 簡書
- [iOS]在運作時為類添加方法
- Runtime中Swizzle時你可能沒注意到的問題 - 簡書
- Hello World
注:本文首發于 iHTCboy's blog ,如若轉載,請注明來源。