前言

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

实现过程

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

具体代码实现

  1. Swizzle category
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    @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. 函数指针对调的实现
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    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

参考