iOS.Tips - Method Swizzling 误区

前言

自己对 Method Swizzling 的误解,希望能帮到有同样误解的朋友。

正文

在 Nshipster 有一篇关于 Method Swizzling 的介绍,里面用到的代码是这样的:

#import "UIViewController+Tracking.h"

#import 

@implementation UIViewController (Tracking)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class class = [self class];
        
        SEL originalSelector = @selector(viewWillAppear:);
        SEL swizzledSelector = @selector(xxx_viewWillAppear:);
        
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        // When swizzling a class method, use the following:
        // Class class = object_getClass((id)self);
        // ...
        // Method originalMethod = class_getClassMethod(class, originalSelector);
        // Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
        
        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    });
}

#pragma mark - Method Swizzling

- (void)xxx_viewWillAppear:(BOOL)animated {
    [self xxx_viewWillAppear:animated];
    NSLog(@"viewWillAppear: %@", self);
}

@end

自己的 viewController 代码:

#import "ViewController.h"

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
}

- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"originalViewWillAppear: %@", self);
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

问:输出什么?
答案是:

originalViewWillAppear: 

为什么在这里 xxx_viewWillAppear: 里的 log 不打印呢?
因为这里 Method Swizzling 所替换的是 UIViewController 类的 viewWillAppear: 方法,而在子类 ViewController 并没有调用到父类的方法,而是重写了这个方法,使得 APP 运行中的代码只有子类的 viewWillAppear:。如果需要父类的方法也调用到,需要在 viewWillAppear: 中加上 [super viewWillAppear:animated];
因此,在编码过程中,需要注意代码规范,生命周期相关的基本 super 调用不能漏写,以防出现难以排查的 BUG。(是的,我就是出现了这种 BUG_(:з」∠)_)。
嗨呀,贼气。

你可能感兴趣的:(iOS.Tips - Method Swizzling 误区)