iOS 黑魔法 Method Swizzling

UIViewController 的 Category

#import "UIViewController+Test.h"
#import <objc/runtime.h>

@implementation UIViewController (Test)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method originalMethod = class_getInstanceMethod(self, @selector(viewWillAppear:));
        Method swizzledMethod = class_getInstanceMethod(self, @selector(hook_viewWillAppear:));
        method_exchangeImplementations(originalMethod, swizzledMethod);
    });
}

- (void)hook_viewWillAppear:(BOOL)animated {
    NSLog(@"开始埋点   0");
    [self hook_viewWillAppear:animated];
    NSLog(@"开始埋点   1");
}

@end

ViewController 继承自 ViewControllerB
ViewControllerB 继承自 ViewControllerC

在 ViewController.m 引入 #import "UIViewController+Test.h" 文件

然后在ViewController、ViewControllerA、ViewControllerB 修改代码如下:

- (void)viewDidLoad {
    
    NSLog(@"%s  ----->  1",__func__);
    
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    NSLog(@"%s  -----> 2",__func__);
}

运行程序,输出下面结果:

-[ViewController viewDidLoad]  ----->  1
-[ViewControllerB viewDidLoad]  ----->  1
-[ViewControllerA viewDidLoad]  ----->  1
-[ViewControllerA viewDidLoad]  -----> 2
-[ViewControllerB viewDidLoad]  -----> 2
-[ViewController viewDidLoad]  -----> 2
开始埋点   0
开始埋点   1

同类不同Category同一个方法的注意

不能名字一样

如:

#import "UIViewController+Test2.h"
#import <objc/runtime.h>

@implementation UIViewController (Test2)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Method originalMethod = class_getInstanceMethod(self, @selector(viewWillAppear:));
        Method swizzledMethod = class_getInstanceMethod(self, @selector(hook_viewWillAppear2:));
        method_exchangeImplementations(originalMethod, swizzledMethod);
    });
}

- (void)hook_viewWillAppear2:(BOOL)animated {
    NSLog(@"开始埋点2     0");
    [self hook_viewWillAppear2:animated];
    
    NSLog(@"开始埋点2     1");
}

@end

有点好奇怪,即使不引入,UIViewController+Test2.h,也会自动引入,不知道是不是因为引入了UIViewController+Test.h,导致自动引入。。。
假如两个文件的方法:- (void)hook_viewWillAppear:(BOOL)animated 都一样,将不会执行,不一样就会一起执行。

-[ViewController viewDidLoad]  ----->  1
-[ViewControllerB viewDidLoad]  ----->  1
-[ViewControllerA viewDidLoad]  ----->  1
-[ViewControllerA viewDidLoad]  -----> 2
-[ViewControllerB viewDidLoad]  -----> 2
-[ViewController viewDidLoad]  -----> 2
开始埋点   0
开始埋点2     0
开始埋点2     1
开始埋点   1