iOS 运行时是每一个 iOS 开发者离不开的话题。利用运行时的消息转发,能够帮助我们完成很多动作。我们熟悉的 Method Swizzling(又称黑魔法),切面编程(AOP)、无侵入埋点等都是依靠此来完成的。
讲到 Method Swizzling,自然离不开下面几个核心方法:
class_addMethod
class_replaceMethod
method_exchangeImplementations
method_setImplementation
class_addMethod
class_addMethod
是给目标类添加一个方法和方法的实现。添加成功会返回 YES,否则返回 NO(例如,如果该类已经存在这个方法)。需要注意的是,class_addMethod
会重写父类的实现(前提是子类没有实现父类的方法,否则也会失败)。总结下来就是 class_addMethod
并不会替换类已有的实现,只能添加新的实现。
class_replaceMethod
class_replaceMethod
用于替换目标类给定方法的实现。可以有两种不同的使用方式:
- 如果方法在该类中不存在的时候,会添加这个方法,效果同
class_addMethod
- 如果方法在该类中存在的时候,会替换该方法的实现,效果同
method_setImplementation
所以在进行 Method Swizzling 的时候,就可以有不同的方式来实现。
method_exchangeImplementations
method_exchangeImplementations
交换两个方法的实现。相当于执行了两次 method_setImplementation
的原子版本。
如果你只想替换某个方法的实现,就可以只调用 method_setImplementation
了。
IMP imp1 = method_getImplementation(m1); |
这是一个例子
当源方法在类中有实现时
可以直接使用 method_exchangeImplementations
将两个方法的实现交换。
@interface Car : NSObject |
Car *car = [[Car alloc] init]; |
当源方法只在父类中有实现
@interface Car : NSObject |
Car *car = [[Car alloc] init]; |
如果直接交换方法的实现,输出会变成下面这样,即执行上述代码注释部分
Car *car = [[Car alloc] init]; |
仔细观察,你会发现,父类的方法实现也被交换了。