????在之前學習runtime的過程中,我發現方法交換有兩種寫法,一開始對對一種寫法不太能理解,后來自己寫demo來試驗了一下以后就知道他是怎么回事了,其實這不是兩種寫法,準確的來說,只是這樣寫更嚴謹一點。
在做試驗之前,首先你得了解以下三個方法的具體作用
- class_addMethod(添加方法,如方法已經存在,則添加失敗)
- class_replaceMethod(替換方法)
- method_exchangeImplementations(方法交換,使用前提,兩個方法都必須存在)
下面給出代碼:
@interface ViewController : UIViewController
- (void)systemMethod_PrintLog;
- (void)ll_imageName;
@end
+(void)load{
SEL originalSelector = @selector(systemMethod_PrintLog);
SEL swizzledSelector = @selector(ll_imageName);
Method originalMethod = class_getInstanceMethod(self, originalSelector);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
BOOL didAddMethod =
class_addMethod(self,
originalSelector,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(self,
swizzledSelector,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- (void)ll_imageName{
NSLog(@"愁啊愁,白了頭");
}
- (void)viewDidLoad {
[super viewDidLoad];
[self ll_imageName];
}
從上面我們可以看到,我只是寫了ll_imageName這個方法的實現,原來的方法systemMethod_PrintLog我并沒有寫它的實現。那么因為此時originalSelector方法選擇器中的實現是不存在的,所以class_addMethod方法就將ll_imageName方法的實現給加入到originalSelector方法選擇器中,此時相當于讓A的去接收B的實現。然后走class_replaceMethod方法,將swizzledSelector選擇器的實現跟originalSelector的實現互相交換,看到這里,你應該已經猜到,無論如何交換,A,B兩個選擇器的實現都是一樣的。
我們看看分別調用兩個方法的結果
1.調用systemMethod_PrintLog,從圖中可以看到實際執行的是ll_imageName的實現。
2.調用ll_imageName,從圖中弄可以看到,它還是執行的是ll_imageName的實現。
結論:當原方法只是聲明了并沒實現時,咱們需要對其做處理,處理的方法就是把需要替換的方法實現給原方法。這種情況下,調用兩個方法中的任何一個方法,他們的實現都是走的替換方法。
另一種情況就是當兩個方法都存在的時候,就走下面的method_exchangeImplementations來進行方法的交換
總結:方法交換的這兩種方法其實,replaceMethod是對原方法沒有實現的一種補充說明。在寫代碼的過程中,盡量咱們應該盡量寫全。