美文网首页
iOS方法拦截替换理解

iOS方法拦截替换理解

作者: sjeffery | 来源:发表于2019-01-27 10:47 被阅读19次

我们经常使用方法拦截替换,有些时候不假思索就直接copy代码用上了。但是这一次希望我们能好好理解下代码为什么这样写。

我们简单介绍一下上面用到的几个方法,首先理解下class_getInstanceMethod,官方解释:

@return The method that corresponds to the implementation of the selector specified by 

 *  \e name for the class specified by \e cls, or \c NULL if the specified class or its 

 *  superclasses do not contain an instance method with the specified selector.

如果当前类或者父类包含该实例方法则返回Method,如果不存在返回NULL。

class_addMethod:向类添加方法跟IMP。如果添加成功返回YES,反之NO。

class_replaceMethod:替换类的方法的IMP。

method_exchangeImplementations:直接交换method的IMP。

方法理解起来都比较直观。接下来讲述一下大致逻辑:

1.在类别load中通过dispatch_once仅调用一次。

2.获取到SEL。

3.通过class_getInstanceMethod获取到Method。

4.通过class_addMethod向该类添加实例方法。

5.如果添加成功,则通过class_replaceMethod将原方法的IMP替换到新方法。如果添加失败,则说明该类已有该实例方法,则直接通过method_exchangeImplementations交换两个方法。

那么会有人问了平时class_addMethod都是返回NO,方法替换都是直接使用method_exchangeImplementations,那什么情况下class_addMethod会返回YES。就像官方介绍的只要该类没有该实例方法成功添加之后就会返回YES,那我都打算拦截替换方法了怎么还有可能出现该类没有该实例方法。如果没有的话那前面的Method获取不就是个0x0吗,那不是跟我们预期的不就有差别了吗。

接下来我们通过个例子说明一下:

起初有一个People类实现了test方法,在People的category:People+track中使用方法new_test替换test。在外部使用初始化people并调用test的时候会发现调用了new_test方法。

然后现在有一个类Chinese继承于People,内部实现了test方法,People+track中不执行任何操作,在People的category:Chinese+track中使用方法new_test替换test。在外部使用初始化Chinese并调用test的时候会发现调用了new_test方法。

接下来Chinese中不实现test方法,过程就有点不一样了。如果Chinese没有实现方法A,而是Chinese的父类People实现了方法test,class_getInstanceMethod是通过SEL在该类或者superclasses获取实例方法,所以这个时候Method还是有的。就不存在之前说的0x0的情况了。这个时候TESTVC确实没有实现方法test所以class_addMethod返回了YES,然后再通过class_replaceMethod将原方法IMP替换到新方法。如果方法替换不去判断当前类是否有该实例方法,那么就会将父类的实例方法跟新方法进行替换,那样有时候结果就会有些偏差了。

相关文章

网友评论

      本文标题:iOS方法拦截替换理解

      本文链接:https://www.haomeiwen.com/subject/ajmjjqtx.html