runtimeiOS Developerruntime runloop

SwizzlingMethod中class_addMethod方

2017-06-16  本文已影响283人  hecong2735

一般的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也就是我们自己方法的实现去实现它。然后再把父类方法的实现替换给我们自己的方法。这样就将originSELdestSEL的实现进行了交换。

tips:
1.SwizzlingMethod中使用dispatch_once的原因是防止有人手动调用load方法,造成交换不止进行了一次。
2.为什么要在load方法中写SwizzlingMethod,参考SwzzlingMethod最佳实践

上一篇下一篇

猜你喜欢

热点阅读