美文网首页
iOS-Method-Swizzling

iOS-Method-Swizzling

作者: 御雪飞斐 | 来源:发表于2019-03-25 16:23 被阅读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方法!!!

    相关文章

      网友评论

          本文标题:iOS-Method-Swizzling

          本文链接:https://www.haomeiwen.com/subject/otlbvqtx.html