iOS Method Swizzling

前言

有个奇怪的需求:每个UIViewController在viewDidAppear:和viewWillAppear:方法中都需要执行一些操作。这里介绍一种iOS Method Swizzling方法:让viewDidAppear:和customViewDidAppear:方法调换实现方式;让viewWillAppear:和customViewWillAppear:方法调换实现方式。

实现过程

  1. 新建UIViewController的一个category - Swizzle
    1. 在Swizzle中实现customViewDidAppear:方法和customViewWillAppear:方法。
    2. 并且重写load方法,在load方法中将指向viewDidAppear:实现的指针和指向customViewDidAppear:实现的指针对调;将指向viewWillAppear:实现的指针和指向customViewWillAppear:实现的指针对调
  2. 函数指针对调实现
  3. 在AppDelegate.m中import这个Swizzle category。那么在所有的UIViewController执行load方法时都会执行Swizzle中重写的load方法,以实现方法的对调;所以之后正常调用viewDidAppear:或是viewWillAppear:时,其实是调用的customViewDidAppear:和customViewWillAppear:方法

具体代码实现

  1. Swizzle category

         @implementation UIViewController (Swizzle)
    
         + (void)load {
             swizzleAllViewController();
         }
    
         - (void)customViewDidAppear:(BOOL)animated {
             // do something here
             [self customViewDidAppear:animated]; // 其实是调用的viewDidAppear:
         }
    
         - (void)customviewWillAppear:(BOOL)animated {
             // do something here
             [self customviewWillAppear:animated]; // 其实是调用的viewWillAppear:
         }
    
         @end
    
         // 函数指针对调
         void swizzleAllViewController() {
             Swizzle([UIViewController class], @selector(viewDidAppear:), @selector(customViewDidAppear:));
             //Swizzle([UIViewController class], @selector(viewWillDisappear:), @selector(customViewWillDisappear:));
             Swizzle([UIViewController class], @selector(viewWillAppear:), @selector(customviewWillAppear:));
         }
    
  2. 函数指针对调的实现

         void Swizzle(Class c, SEL origSEL, SEL newSEL) {
             Method origMethod = class_getInstanceMethod(c, origSEL);
             Method newMethod = nil;
             if (!origMethod) {
                 origMethod = class_getClassMethod(c, origSEL);
                 if (!origMethod) {
                     return;
                 }
                 newMethod = class_getClassMethod(c, newSEL);
                 if (!newMethod) {
                     return;
                 }
             } else {
                 newMethod = class_getInstanceMethod(c, newSEL);
                 if (!newMethod) {
                     return;
                 }
             }
    
             if (class_addMethod(c, origSEL, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
                 NSLog(@"vanney code log... errorhappened");
                 class_replaceMethod(c, newSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
             } else {
                 method_exchangeImplementations(origMethod, newMethod);
             }
         }
    

P.S

以上代码都参考自Coding-iOS

参考

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器