下面兩種實現(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);
}
}
- 假設(shè)有兩個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)];
交換前:
使用第一種方案交換后:
此時A類的實例調(diào)用
test
方法烦租,就會發(fā)生崩潰。因為
test
方法屬于A類除盏,B類未實現(xiàn)test
方法叉橱,交換方法導(dǎo)致直接改變了A類方法列表中的結(jié)構(gòu)當A類調(diào)用
test
方法時,其實調(diào)用了btest
方法者蠕,而btest
內(nèi)部[self btest];
此時等價于[A btest];
btest
方法屬于B類窃祝,所以會發(fā)生unrecognized selector
錯誤
使用第二種方案交換后:
利用
class_addMethod
特性,只判斷當前類方法踱侣,不判斷繼承方法為子類重新添加了test
方法粪小,此時方法交換只會影響B(tài)類,不會發(fā)生崩潰