如有转载,请标明出处:iOS runtime如何交换两个类方法
runtime交换实例方法,老生常谈的问题,很多blog都有介绍过,但是好像暂时没有找到过如何交换两个类的类方法。通过对元类的学习,作者自行摸索,终于尝试出如何交换两个类方法。元类的具体内容,见《类对象、元类》一章。
实例方法的交换:
void class_swizzleInstanceMethod(Class class, SEL originalSEL, SEL replacementSEL)
{
//class_getInstanceMethod(),如果子类没有实现相应的方法,则会返回父类的方法。
Method originMethod = class_getInstanceMethod(class, originalSEL);
Method replaceMethod = class_getInstanceMethod(class, replacementSEL);
//class_addMethod() 判断originalSEL是否在子类中实现,如果只是继承了父类的方法,没有重写,那么直接调用method_exchangeImplementations,则会交换父类中的方法和当前的实现方法。此时如果用父类调用originalSEL,因为方法已经与子类中调换,所以父类中找不到相应的实现,会抛出异常unrecognized selector.
//当class_addMethod() 返回YES时,说明子类未实现此方法(根据SEL判断),此时class_addMethod会添加(名字为originalSEL,实现为replaceMethod)的方法。此时在将replacementSEL的实现替换为originMethod的实现即可。
//当class_addMethod() 返回NO时,说明子类中有该实现方法,此时直接调用method_exchangeImplementations交换两个方法的实现即可。
//注:如果在子类中实现此方法了,即使只是单纯的调用super,一样算重写了父类的方法,所以class_addMethod() 会返回NO。
//可用BaseClass实验
if(class_addMethod(class, originalSEL, method_getImplementation(replaceMethod),method_getTypeEncoding(replaceMethod)))
{
class_replaceMethod(class,replacementSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
}else {
method_exchangeImplementations(originMethod, replaceMethod);
}
}
通过如上代码,传入相应的Class及selector,即可交换对应的方法。
类方法的交换:
通过对元类的学习,我们可以知道,其实Class(也就是类)本身也是一个对象,他的类可以通过object_getClass(class)
方法得到,这种类对象的类就叫做元类。所以一个类的类方法,也就是其元类的实例方法,我们可以通过将其元类传入,即可交互类方法。
void class_swizzleClassMethod(Class class, SEL originalSEL, SEL replacementSEL)
{
//类方法实际上是储存在类对象的类(即元类)中,即类方法相当于元类的实例方法,所以只需要把元类传入,其他逻辑和交互实例方法一样。
Class class2 = object_getClass(class);
class_swizzleInstanceMethod(class2, originalSEL, replacementSEL);
}
虽然代码很容易,但是里面的原理并不是很简单。
附上demo