下面兩種實現(xiàn)是在iOS開發(fā)中最常用的方法交換方式,那么兩種實現(xiàn)方式具體有什么區(qū)別呢?
首先,以上兩種實現(xiàn)都可以達到方法交換的效果,但是方案一在某些情況下會發(fā)生崩潰,而方案二相對安全一些。
方案一:
+ (void)swizzleInstanceMethod:(SEL)originalSel with:(SEL)swizzledSel {
Method originalMethod = class_getInstanceMethod(self, originalSel);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSel);
method_exchangeImplementations(originalMethod, swizzledMethod);
}
方案二:
+ (void)swizzleInstanceMethod:(SEL)originalSel with:(SEL)swizzledSel {
Method originalMethod = class_getInstanceMethod(self, originalSel);
Method swizzledMethod = class_getInstanceMethod(self, swizzledSel);
BOOL didAddMethod =
class_addMethod(self,
originalSel,
method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(self,
swizzledSel,
method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
}
- 假設有兩個A、B兩個類,B是A的子類,
@interface A : NSObject
@end
@implementation A
- (void)test {
NSLog(@"test");
}
@end
@interface B : A
@end
@implementation B
- (void)btest {
[self btest];
NSLog(@"btest");
}
@end
- 然后交換B類的方法
[self swizzleInstanceMethod:@selector(test) with:@selector(btest)];
交換前:

image.png
使用第一種方案交換后:

image.png
此時A類的實例調(diào)用
test方法,就會發(fā)生崩潰。因為
test方法屬于A類,B類未實現(xiàn)test方法,交換方法導致直接改變了A類方法列表中的結(jié)構(gòu)當A類調(diào)用
test方法時,其實調(diào)用了btest方法,而btest內(nèi)部[self btest];此時等價于[A btest]; btest方法屬于B類,所以會發(fā)生unrecognized selector錯誤
使用第二種方案交換后:

image.png
利用
class_addMethod特性,只判斷當前類方法,不判斷繼承方法為子類重新添加了test方法,此時方法交換只會影響B(tài)類,不會發(fā)生崩潰