设为首页 加入收藏

TOP

OC方法交换swizzle详细介绍——不再有盲点(四)
2019-08-15 00:11:50 】 浏览:299
Tags:方法 交换 swizzle 详细 介绍 再有 盲点
f的类型判断来避免。

可以比较下交换前后,

交换前:

SwizzleClassTest_swi_viewDidLoadSel -> SwizzleClassTest_swi_viewDidLoadImp

UIViewController_viewDidLoadSel -> UIViewController_viewDidLoadImp

交换后:

SwizzleClassTest_swi_viewDidLoadSel -> SwizzleClassTest_swi_viewDidLoadImp

UIViewController_swi_viewDidLoadSel -> UIViewController_viewDidLoadImp
UIViewController_viewDidLoadSel -> UIViewController_swi_viewDidLoadImp

可以看出 SwizzleClassTest 没有受影响,映射关系不变。

这种想取消的话,也很简单method_exchangeImplementations

最后补充一点:C函数 实现交换

这里讲的是用C函数交换系统类的方法。而不是fishhook的hook C的函数,目标不一样。原理也不一样

还以hook UIViewControllerviewDidLoad为例

上面说到,oc方法调用会转换为objc_msgSend(self,_cmd,param)这种形式,这里再补充一点,objc_msgSend找到imp函数指针后,最终会是imp(self,_cmd,param)调用C函数,imp其实就是个C函数指针。

那么我们可以定义一个C函数,让sel和我们新建的C函数(imp)形成映射。另外还需要记录之前的imp实现,可以定义一个函数指针来保存sel之前的imp实现;大概示意:

之前:
pOriImp = NULL
vcSel -> vcImp
Cfun(){};

之后:

pOriImp = vcImp;
vcSel -> cFun;// 函数名即为函数指针

详细如下:

/// 准备1. 定义一个函数指针,用于记录系统原本的IMP实现,并初始化为NULL
void (*origin_test_viewDidload)(id,SEL) = NULL;

/// 准备2. 定义要交换的函数,里面会调用系统的IMP
static void swizzle_test_viewDidload(id self, SEL _cmd)
{
    // 这里打印的self为UIViewController或者子类实例
    NSLog(@"%@",self);
    if (origin_test_viewDidload) {
        origin_test_viewDidload(self, _cmd);
    }
}

/// 开始交换。startHook可以是某个类的方法或实例方法或C函数都可以
+ (void)startHook {
   static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        Class target = [UIViewController class];
        SEL oriSel = @selector(viewDidLoad);
        // 要交换的函数
        IMP swiImp = (IMP)swizzle_test_viewDidload;
        Method origMethod = class_getInstanceMethod(target, oriSel);
        // 替换之前的先保留
        origin_test_viewDidload = (void *)method_getImplementation(origMethod);
        if (origin_test_viewDidload) {
            // 最后替换,这里用到了set
            method_setImplementation(origMethod, swiImp);
        }
    });
}

这种hook,没有给类的MethodList新增Method,只是替换了实现,对原类改动最小。

和其它hook方式一样,这种对第三方库 的hook,也是不影响。如果第三方库也交换了,均会得到调用

最后,如果你想取消hook,很简单,method_setImplementation为原来的IMP即可。记着把origin_test_viewDidload也置为NULL.

总结

  • 首先要知道方法交换的原理;
  • 熟悉它常用接口;
  • 被交换方法不存在引发的 父类、子类问题;
  • 以及oc中方法的继承、“覆盖”问题;
  • 可能引发重复交换的问题,以及后果;
  • 理解self只是个隐藏参数,并不一定是当前方法所在的类的实例对象

最后,大概三类hook,至于想用哪种,其实无所谓了,看具体场景。但是原理一定要清楚,每次hook时,都要认真推演一遍,计算下可能产生的影响。

首页 上一页 1 2 3 4 下一页 尾页 4/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Swift 面试题 下一篇iOS技术栈-Swift版

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目