下面两种实现是在iOS开发中最常用的方法交换方式,那么两种实现方式具体有什么区别呢?
首先,以上两种实现都可以达到方法交换的效果,但是方案一在某些情况下会发生崩溃,而方案二相对安全一些。
方案一:
+ (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)];
交换前:
使用第一种方案交换后:
此时A类的实例调用
test
方法,就会发生崩溃。因为
test
方法属于A类,B类未实现test
方法,交换方法导致直接改变了A类方法列表中的结构当A类调用
test
方法时,其实调用了btest
方法,而btest
内部[self btest];
此时等价于[A btest];
btest
方法属于B类,所以会发生unrecognized selector
错误
使用第二种方案交换后:
利用
class_addMethod
特性,只判断当前类方法,不判断继承方法为子类重新添加了test
方法,此时方法交换只会影响B类,不会发生崩溃