一、简介
在一个类没有实现源码的情况下,如果你要改变一个类的实现方法,你可以选择重继承该类,然后重写方法,或者使用Category类别名暴力抢先的方式。但是这两种方式,都需要我们在使用的时候改变我们的编程方式,或者继承该类,或者需要引入Category。下面推出的一种方式,不需要我们修改我们编写逻辑的代码,就能实现函数的Hook功能,那就是RunTime中的Method Swizzling—交换方法的实现。
二、实现原理
在Object-C中每一个Method都是由一个SEL(方法名的散列值)和一个方法实现的指针(IMP)组成,他们在类实例化得过程中,SEL和IMP一一对应组成我们需要的完整的Method。
struct method_t {
SEL name;//方法名的散列值
const char *types;//方法的描述
IMP imp;//方法真实实现的指针
};
如果我们不做任何处理,SEL和IMP都是一一对应的。
如果我们使用Method Swizzling交换Method2和Method3的实现的时候,我们只需要在运行时把IMP2和IMP3的指向地址做个交换就可以了。其实我们调用的就是RunTime中的
*/
OBJC_EXPORT void method_exchangeImplementations(Method m1, Method m2)
__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0);
进入它的源码,可以查看它就是按照以上思路把方法指针做了交换,来做到在运行时把方法进行交换。
下面就是它实现的关键源码。
void method_exchangeImplementations(Method m1, Method m2)
{
if (!m1 || !m2) return;
rwlock_writer_t lock(runtimeLock);
if (ignoreSelector(m1->name) || ignoreSelector(m2->name)) {
// Ignored methods stay ignored. Now they're both ignored.
m1->imp = (IMP)&_objc_ignored_method;
m2->imp = (IMP)&_objc_ignored_method;
return;
}
IMP m1_imp = m1->imp;
m1->imp = m2->imp;
m2->imp = m1_imp;
// RR/AWZ updates are slow because class is unknown
// Cache updates are slow because class is unknown
// fixme build list of classes whose Methods are known externally?
f