一般的SwizzlingMethod实现方法:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
SEL originSEL = @selector(setBorderColor:);
Method originMethod = class_getInstanceMethod([self class], originSEL);
SEL destSEL = @selector(setBorderColorFromUIColor:);
Method destMethod = class_getInstanceMethod([self class], destSEL);
BOOL addSuccess = class_addMethod([self class], originSEL, method_getImplementation(destMethod), method_getTypeEncoding(destMethod));
if (addSuccess) {
class_replaceMethod([self class], destSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
}
method_exchangeImplementations(originMethod, destMethod);
});
首先看下class_addMethod
方法:
class_addMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>);
其中四个参数分别是:要添加方法的类、方法的名字、方法的实现和方法的参数。返回一个BOOL值,如果类中已经存在该方法,则返回NO,如果类中不存在该方法,则返回YES。
然后是class_replaceMethod
方法:
class_replaceMethod(<#__unsafe_unretained Class cls#>, <#SEL name#>, <#IMP imp#>, <#const char *types#>)
class_replaceMethod
的执行分两种情况:
1.类中没有被替代的方法,执行class_addMethod
;
2.类中有要被替代的方法,执行method_setImplementation
;
至于为什么要先用class_addMethod
方法做一次判断,是因为我们要替换的方法有可能并没有在这个类中被实现,而是在他的父类中实现的,这个时候originSEL
获取到的方法就是他父类中的方法。所以我们要在当前的类中添加一个originSEL
方法,但是用destSEL
也就是我们自己方法的实现去实现它。然后再把父类方法的实现替换给我们自己的方法。这样就将originSEL
和destSEL
的实现进行了交换。
tips:
1.SwizzlingMethod中使用dispatch_once
的原因是防止有人手动调用load方法,造成交换不止进行了一次。
2.为什么要在load方法中写SwizzlingMethod,参考SwzzlingMethod最佳实践
网友评论