方法交换(method swizzing)及其实际应用

简介

在Objective-C中,对象收到消息之后,究竟会调用哪个方法需要在运行时才能确定。查找消息的唯一依据是selectorselector与相应的IMP对应,利用Objective-C的动态特性,可以实现在运行时替换selector对应的IMP,这就是方法交换。

注:在Objective-C中,每个类都有一个方法列表(即objc_class结构体中的methodLists),里面存放着selector的名字与IMP的映射关系。




相关的API

  • class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)

    • 作用:替换类中指定方法的实现,当类中没有想替换的目标方法时,它会调用class_addMethod来为该类增加目标方法。
  • method_exchangeImplementations(Method m1, Method m2)

    • 作用:交换两个方法的实现(注:内部实现就是调用了两次method_setImplementation方法)
  • method_setImplementation(Method m, IMP imp)

    • 作用:设置一个方法的实现




实际应用

应用一:检查类的dealloc有没有执行(以UIViewController为例)

  1. #import "UIViewController+Dealloc.h"
  2. #import <objc/runtime.h>
  3. @implementation UIViewController (Dealloc)
  4. + (void)load {
  5. static dispatch_once_t onceToken;
  6. dispatch_once(&onceToken, ^{
  7. Method method1 = class_getInstanceMethod(self, NSSelectorFromString(@"dealloc"));
  8. Method method2 = class_getInstanceMethod(self, @selector(my_dealloc));
  9. method_exchangeImplementations(method1, method2);
  10. });
  11. }
  12. - (void)my_dealloc {
  13. NSLog(@"%@销毁了", self);
  14. [self my_dealloc];
  15. }
  16. @end




注意

  • 交换方法应该只在+load中完成
  • 交换方法应该只在dispatch_once中完成,确保只会被执行一次。
  • 在交换方法实现后,记得要调用原生方法的实现(除非你非常确定可以不用调用原生方法的实现)。
  • 确保调用了原生方法的所有地方,不会因为你交换了方法的实现而出现意想不到的结果。




参考资料