我们有时候需要拦截hook 下系统的方法,在系统方法被调用之前先调用我们的方法,然后再调用系统的方法,这样我们可以做些额外的事情,比如KVO 的实现也用到了类似的方法。
下面我们实践下 ,我们重写 UIViewController 的 viewDidLoad 方法, 替换掉 系统的viewDidLoad 后,我们再调用系统的viewDidLoad的实现。
主要用到的函数: method_exchangeImplementations
代码如下:
+(void) initialize {
SEL originLoadSel = @selector(viewDidLoad);
SEL myViewLoadSel = @selector(myViewDidLoad);
Method originLoadMethod = class_getInstanceMethod([self class], originLoadSel);
Method myLoadMethod = class_getInstanceMethod([self class], myViewLoadSel);
method_exchangeImplementations(originLoadMethod, myLoadMethod);
}
- (void) myViewDidLoad {
NSLog(@"my custom ViewDidLoad");
//call real viewDidLoad
[self myViewDidLoad];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
NSLog(@"origin viewDidLoad");
}
运行代码,可以看到 先输出: my custom ViewDidLoad , 然后再输出 origin viewDidLoad.
原理也很简单:就是替换了 viewDidLoad 和 myViewDidLoad 这两个 Method 的 SEL 所对应的 IMP 实现, viewDidLoad 的 SEL 被替换为了 myViweDidLoad 这个Method 的 IMP , 反之, myViewDidLoad 的 Method 的 IMP 对应了 系统的原生 viewDidLoad的IMP。