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方法!!!

上一篇下一篇

猜你喜欢

热点阅读