@implementatio...">
美文网首页
iOS runtime

iOS runtime

作者: 雪丹妮_66865 | 来源:发表于2019-09-25 15:28 被阅读0次

import "CXDHook.h"

import <objc/runtime.h>

@implementation CXDHook

  • (void)hookClass:(Class)classObject fromSelector:(SEL)fromSelector toSelector:(SEL)toSelector {
    Class class = classObject;
    //得到被交换类的实例方法
    Method fromMethod = class_getInstanceMethod(class, fromSelector);
    //得到交换类的实例方法
    Method toMethod = class_getInstanceMethod(class, toSelector);

    //class_addMethod()函数返回成功表示交换的方法没实现,然后通过class_addMethod()函数先实现;返回失败则表示被交换方法已存在,可以直接进行IMP指针交换
    if (class_addMethod(class, fromSelector, method_getImplementation(toMethod), method_getTypeEncoding(toMethod))) {
    //进行方法的交换
    class_replaceMethod(class, toSelector, method_getImplementation(fromMethod), method_getTypeEncoding(fromMethod));
    } else {
    //交换IMP指针
    method_exchangeImplementations(fromMethod, toMethod);
    }
    }

但是,像上面这段代码一样,直接使用Runtime的方法进行方法交换会有很多风险,RSSwizzle库里指出了四个典型的直接使用Runtime方法进行方法交换的风险。
第一个风险是,需要在+load方法中进行方法交换。因为如果在其他时候进行方法交换,难以保证另外一个线程中不会同时调用被交换的方法,从而导致程序不能按预期执行。

第二个风险是,被交换的方法必须是当前类的方法,不能使父类的方法,直接把父类的实现拷贝过来不会起作用。父类的方法必须在调用的时候使用,而不是方法交换时使用。

第三个风险是,交换的方法如果依赖了cmd,那么交换后,如果cmd发生了变化,就会出现各种奇怪问题,而且这些问题还很难排查。特别是交换了系统方法,你无法保证系统方法内部是否依赖了cmd。

第四个风险是,方法交换命名冲突。如果出现冲突,可能会导致方法交换失败。

更安全的方法交换库Aspects
Aspects是一个通过Runtime消息转发机制来实现方法交换的库。它将所有的方法调用都指到_objc_msgForward函数调用上,按照自己的方式实现了消息转发,自己处理参数列表,处理返回值,最后通过NSInvocation调用来实现方法交换。同时Aspects还考虑了一些方法交换可能会引发的风险,并进行了处理。

Aspects实现方法交换的原理:
Aspects的整体流程是,先判断是否可以进行方法交换。这一步会进行安全问题的判断处理。如果没有风险的话,再针对要交换的是类对象还是实例对象分别进行处理。

相关文章

网友评论

      本文标题:iOS runtime

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