Method Swizzling详解

1. method-swizzling 是什么?

Method-Swizzling实际就是更换方法所对应的实现函数,其主要作用是在运行时将一个方法的实现替换成另一个方法的实现,这就是我们常说的 iOS黑魔法。Method-Swizzling比较常用的应用是防止数组、字典越界等

方法交换示意图.png

下面代码是否会递归调用呢?答案是不会的,因为方法交换后,yj_studentInstanceMethod实际上是通过[self personInstanceMethod]调用的,而[self yj_studentInstanceMethod] 则是调用 personInstanceMethod,所以不会递归调用

是否会递归调用.png

2. method-swizzling 坑点

2.1 method-swizzling使用过程中确保只执行一次

method-swizzling 多次调用会导致方法的重复交换,无法保证是否达到了最终的交换效果。如何解决这个问题呢?

解决方案:

+load 方法中执行,且使用 dispatch_once包裹;这样就可以保证方法交换只执行一次

方法交换.png

2.2 子类没有实现,父类实现了

如果交换的方法在子类中没有实现(继承自父类的方法),父类里有实现,那么交换的时候会不会报错呢?

坑点二.png

运行后发现报错了。这是因为personInstanceMethod 已经交换成了 yj_studentInstanceMethod 。而在 yj_studentInstanceMethod 里面调用了 [self yj_studentInstanceMethod],而 YJPerson 里面没有 yj_studentInstanceMethod 方法,所以报错。

魔法坑点二 报错.png
解决方案:

先通过 class_addMethod 尝试给自己添加要交换的方法,如果添加成功,即表明类中没有这个方法,则通过 class_replaceMethod 进行替换,如果添加失败则说明类中有这个方法,正常进行 method_exchangeImplementations

坑点二解决方案.png
2.3 父类子类都没有实现。

如果父类子类都没有实现,会有什么问题呢?运行后发现会递归调用。那么说明没有交换成功。所以 yj_studentInstanceMethod 还是指向自己的imp。当调用 personInstanceMethod 之后,会进入 yj_studentInstanceMethod ,之后 [self yj_studentInstanceMethod] 就会无限递归调用自己,最终导致栈溢出

解决方案:

判断 oriMethod 是否为空,如果为空则 添加swiMethod 方法并且 添加imp实现

坑点三解决方案.png

Demo链接

你可能感兴趣的:(Method Swizzling详解)