• Objective-c runtime方法替换引发的死循环


    在OC中:
    API: class_addMethod往一个Class里添加method
    API: class_getInstanceMethod或class_getClassMethod可以判断某个SEL是否存在于Class
    API: method_exchangeImplementations 交换方法。
     
    最近工作上做了一件事,简单点说就是需要把一些特定Class里的方法func,替换成Hook_func,当Hook_func执行完之后,再执行func。于是很简单地想到了往Class添加一个Hook_func,然后再交换func与Hook_func,就能到达目的。
     
    但是,在实现后,却出现了死循环,纠其原因,因为部分Class间存在着继承关系,没有正确地将Method添加到正确的Class中导致。
     
    当时为了解决这个问题,重新去理清楚了一下Class中 SEL 与 Method的关系。SEL是一个选择器,相当于指向一个Method的指针,将SEL指向不同的Method,它就会有不一样的特性,method_exchangeImplementations也就是交换SEL指向的Method值来实现方法交换的。
     
    在调用class_getInstanceMethod时,是会检查superClass的。
     
    如下图,当ClassB继承ClassA时, ClassB中没有SEL func,而ClassA中有SEL func。
     
     
     
    这时调用class_getInstanceMethod(ClassB, @selector(func)),是能拿到SEL func的Method的,然后再将ClassB中添加SEL Hook_func后,变成下图。
     
    对ClassB调用method_exchangeImplementations后,得到下图。
     
    这里可以看到,其实ClassA中的SEL:func已经是指向Method:Hook_func。在对ClassB的实例调用SEL:func时,能达到之前预订的效果,即先执行Hook_func后再执行func。
    但在这个时候,如果再对ClassA做类似ClassB的处理,将得到下图:
    这时SEL:func和SEL:Hook_func都指向了Method:Hook_func,于是便出现了死循环的问题。
     
    最终的解决方法从上图已经可以很明显的看出来了,即在对ClassB做处理的时候,添加的SEL:Hook_func不应该添加到ClassB上,而应该添加到ClassA上,如下图,则问题得已解决。
     
    执行下面的这个函数,找到正确的Class,然后再往Class里添加方法和交换方法,问题就解决了:
     Class GetSelectorInsClass(Class hclass, SEL sel, Method sel_method) {
        Class super_class = [hclass superclass];
        if (!super_class) {
            return hclass;
        }
        Method method = class_getInstanceMethod(super_class, sel);
        if (method != sel_method) {
            return hclass;
        }
        return GetSelectorInsClass(super_class, sel, sel_method);
    }
     
  • 相关阅读:
    分时段查询数据
    优秀产品经理的7大核心技能
    控制台打印螺旋数组
    强大的jquery,再次让我为之鼓掌——三维展示插件
    立象条码打印机PPLB类单双标签打印
    一次与德国程序员的交流
    用ASP为Discuz扩展点小功能
    GDI+ 小破孩动画
    回应YeanJay同学jQuery按钮改变DIV背景色
    C# Dock Style 设置
  • 原文地址:https://www.cnblogs.com/aizquan/p/6362845.html
Copyright © 2020-2023  润新知