在swift里面有个非常有意思的特性,那就是AOP,可以为协议增加默认实现。那么在Objc里面也有个类似的工具类Aspect,虽然还是有很多缺陷。这次我们来看看Aspect的实现方式。
第一想法Aspect就是通过method swizzling来实现方法的替换的,然而实际上并不是这样的。让我们来考虑几种场景:
- 对已有的类进行hook方法。
- 对一个实例对象hook方法。
如果是单纯的method swizzling,以上两者是一模一样的结果的。那么Aspect是如何实现的呢?
对象
Aspect的类型主要分两种:
- 对类层面进行的hook。包括类和元类(meta class),也就是
-
方法和+
方法。在Objc中类和元类的实现是一致的,所以采用的方式也是一致的。 - 对实例层面进行的hook。这里的实现比较像KVO的实现方式,也就是会利用runtime自动生成一个子类,子类来实现消息的转发,这样就不会影响到其他实例了。
方法
Aspect并不直接method swizzling具体的方法,而是利用了forward message的特性。
/* Message Forwarding Primitives
* Use these functions to forward a message as if the receiver did not
* respond to it.
*/
void _objc_msgForward(void /* id receiver, SEL sel, ... */ )
Aspect将所有消息都转发到这个方法,然后统一从forwardInvocation:
中处理。这样就可以统一管理,并且统一处理多种不同类型的消息了。
强校验
Aspect还对hook方法进行了强校验,避免不同参数的方法调用导致的crash。
应用
最大的应用场景就是单元测试了,和其他测试库一起配合使用还是非常方便的。当然也可以用于应用内的method swizzling,如果你的需求够大的话。