程序员

Runtime-方法交换

2017-11-24  本文已影响0人  vincentgemini

在iOS开发中,有一种编程方式叫面向切面编程(AOP),这种编程最大好处是,在不修改源代码的前提下,在原有功能上添加新功能,常见的就是埋点需求。今天要说的是,实现AOP时常用的方法,OC运行时的方法交换(swizzleMethod)。

说到方法交换,这里就有两个东西要说:SEL和IMP。SEL其实就是一个整形标识,用来唯一标识一个方法名而已。而IMP是一个函数指针,表示方法实现的代码块地址。每一个SEL都会对应一个IMP,但是,IMP可能会被多个SEL对应。当做方法交换时,其实交换的是SEL与IMP的对应关系,如下图。

图片.png

交换后的效果就是,当调用对象的selectorA方法时,执行的是IMPb代码块的实现。用到的相关代码如下:

static inline void swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
    Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
    Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
    method_exchangeImplementations(originalMethod, swizzledMethod);
}

上面提到面向切面编程,那么仅仅交换方法是不够的,还需要返回原函数。这时,往往是在IMPb实现里面调用self selectorB,表面看方法里面调用自己,会出现死循环,但由于做了方法交换,实际的情况就是这样的:当调用对象selectorA方法时,执行的是IMPb的实现,而IMPb实现中又调用了selectorB,由于做了方法交换,此时执行的是IMPa的实现,这样就达到了在调用selectorA前先执行了selectorB对应的IMPb的实现,然后又继续执行IMPa的实现。

通常以上实现会借助类别,在load方法中,执行类内方法与类别新定义方法进行交换,类别新方法调用自身方法达到回到原函数的效果。实际交换的对象是本类的方法。除此之外,方法交换也可以交换父类与子类方法,也可以没有关系的两个类之间方法。

下面主要说说在使用方法交换的时候,需要注意以下几点:

由于Runtime的方法交换用处比较多,本人经验有限,也希望大家提出意见和新的用法。本人也会在今后的开发中补充此文章。
所有代码可以到本的Github下载。

上一篇 下一篇

猜你喜欢

热点阅读