在网上看到了一段swizzle method的代码,想起AFNetworking也有类似的写法,重点留意了一下。第一感觉是在64行执行过class_addMethod后,originalSelector和swizzledSelector应该都是指向同一个Implementation,为什么还要在70行再执行class_replaceMethod呢?

写了小demo测试了一下,要执行class_addMethod有两种情况:
1. 类本身没有实现某个方法
2.该类的父类实现了某个方法,但是类本身没有实现该方法。
分别讨论一下:
1.当类本身没有实现某个方法,originalMethod为nil。此时执行class_addMethod方法,将swizzledMethod的IMP赋给originalMethod。然后执行class_replaceMethod,但此时的72行得到的IMP仍然是nil。正常来说replace后swizzledMethod的IMP应该为nil。但是才76行打log发现originalMethod和swizzledMethod的IMP都指向swizzledMethod的IMP,并没有得到预想的结果。
此外打log还有新的发现:在class_addMethod后,这个类里对应该selector的method已经变了,调用class_getInstanceMethod(class, originalSelector)后发现和原来的originalMethod并非同一个。遂去查了class_replaceMethod的源码,其内部也是调用了class_addMethod,另外传递了一个replace的bool值。在class_addMethod调用了_method_setImplementation,在setImp中判断了传入的imp,是nil,所以直接return nil了,class_replaceMethod并没能执行成功!而且注意到class_replaceMethod方法是有返回值的,也返回了nil,印证了之前的推测。



2.该类的父类实现了某个方法,但是类本身没有实现该方法。此时originalMethod为父类的实现。而在当前类并未实现,也执行了class_addMethod。将swizzledMethod的IMP赋给originalMethod。给当前类增加了swizzledMethod的IMP。然后执行class_replaceMethod,而此时传入的参数method_getImplementation(originalMethod)其实是该方法的父类的实现。replace后的结果为:当前类的该方法新增了swizzledMethod的IMP,而swizzledMethod的IMP变成了父类的该方法的IMP,父类该方法本身没有任何改变。
网友评论