iOS-Method-Swizzling
2019-03-25 本文已影响0人
御雪飞斐
选择子名称相对应的方法是可以在运行期被改变的,所以,我们可以不用通过继承类并覆写方法就能改变这个类本身的功能。
如何在运行期改变选择子对应的方法呢? 答:通过操纵类的方法列表的IMP指针。
什么是类方法表?什么是IMP指针呢?
类的方法列表会把选择子的名称映射到相关的方法实现上,使得“动态消息派发系统”能够据此找到应该调用的方法。这些方法均以函数指针的形式来表示,这些指针叫做IMP。
交换lowercaseString和uppercaseString方法的实现:
Method originalMethod = class_getInstanceMethod([NSString class], @selector(lowercaseString));
Method swappedMethod = class_getInstanceMethod([NSString class],@selector(uppercaseString));
method_exchangeImplementations(originalMethod, swappedMethod);
这时,如果我们调用lowercaseString方法就会实际调用uppercaseString的方法,反之亦然。
实际应用中,只交换已经存在的两个方法是没有太大意义的。我们应该利用这个特性来给既有的方法添加新功能(听上去吊吊的):
它的实现原理是:先通过分类增加一个新方法,然后将这个新方法和要增加功能的旧方法替换(旧方法名 对应新方法的实现),这样一来,如果我们调用了旧方法,就会实现新方法了。
实例一:
先将新方法写在NSString的分类里:
@interface NSString (EOCMyAdditions)
- (NSString*)eoc_myLowercaseString;
@end
@implementation NSString (EOCMyAdditions)
- (NSString*)eoc_myLowercaseString {
NSString *lowercase = [self eoc_myLowercaseString];//eoc_myLowercaseString方法会在将来方法调换后执行lowercaseString的方法
NSLog(@"%@ => %@", self, lowercase);//输出语句,便于调试
return lowercase;
}
@end
交换两个方法的实现(操纵调换IMP指针):
Method originalMethod =
class_getInstanceMethod([NSString class],
@selector(lowercaseString));
Method swappedMethod =
class_getInstanceMethod([NSString class],
@selector(eoc_myLowercaseString));
method_exchangeImplementations(originalMethod, swappedMethod);
我们交换了lowercaseString和eoc_myLowercaseString的方法实现,那么在调用原来的lowercaseString方法后就可以输出新增的语句了。
“NSString *string = @"ThIs iS tHe StRiNg";
NSString *lowercaseString = [string lowercaseString];
// Output: ThIs iS tHe StRiNg => this is the string”
实例二:
Method viewDidAppear = class_getInstanceMethod(self.class, @selector(viewDidAppear:));
Method wlt_viewDidAppear = class_getInstanceMethod(self.class, @selector(wlt_viewDidAppear:));
method_exchangeImplementations(viewDidAppear, wlt_viewDidAppear);
- (void)wlt_viewDidAppear:(BOOL)animate {
[self wlt_viewDidAppear:animate];
//写一些自己的代码
}
注://这里调用wlt_viewDidAppear,并不会循环调用,实际上调用的是viewDidAppear方法!!!