美文网首页
iOS Runtime之方法替换

iOS Runtime之方法替换

作者: 谢二九 | 来源:发表于2022-06-24 08:21 被阅读0次

    Runtime系列导读

    简介

    Method Swizzling,顾名思义,就是交换两个 方法的实现。简单来说,就是利用Objective-C Runtime的动态绑定特性,将一个方法的实现与另 一个方法的实现进行交换。

    分析

    数据结构

    • objc_method
      • 我们从上面的结构体中发现一个objc_method字段,它的定义如下:


        image.png
    • 我们从上面的结构体中还发现,一个方法由如下三部分组成。
      • method_name:方法名。
      • method_types:方法类型。
      • method_imp:方法实现。

    交换原理

    • 使用Method Swizzling交换方法,其实就是修改了objc_method 结构体中的mthod_imp,即改变了method_name和method_imp的映射关系如下:
    image.png
    • 看一个例子
    @implementation NSObject (Swizzler)
    
    + (void)swizzleInstanceMethodWithOriginalSEL:(SEL)originalSel SwizzleNewSEL:(SEL)newSel {
        
        Method originalMethod = class_getInstanceMethod(self, originalSel);
        Method newMethod = class_getInstanceMethod(self, newSel);
        if (!originalMethod || !newMethod) {
            return;
        }
        //加一层保护措施,如果添加成功,则表示该方法不存在于本类,而是存在于父类中,不能交换父类的方法,否则父类的对象调用该方法会crash;添加失败则表示本类存在该方法
        BOOL addMethod = class_addMethod(self, originalSel, method_getImplementation(newMethod), method_getTypeEncoding(newMethod));
        if (addMethod) {
            //再将原有的实现替换到swizzledMethod方法上,从而实现方法的交换,并且未影响到父类方法的实现
            class_replaceMethod(self, newSel, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
        }else{
            method_exchangeImplementations(originalMethod, newMethod);
        }
    }
    
    @end
    

    答疑

    如何hook一个对象的方法,而不影响其它对象

    设置isa指向的ClassClass object_setClass(id obj, Class cls)

    GXPerson* person = [GXPerson new];
    [person test];
    object_setClass(person, [GXPerson2 class]);
    [person test];
    

    class_replaceMethod和class_addMethod区别

    • class_replaceMethod是替换某个类的方法的实现,功能上可以替代class_addMethod, 但是class_addMethod只能在SEL没有IMP指向时才可以添加成功,而class_replaceMethod不管SEL 有没有`IMP实现,都可以添加成功

    class_replaceMethod和method_exchangeImplementations的不同

    • 当使用class_replaceMethod替换父类的方法时,只有在子类里面调用才有效,实际上是在子类里面重写了父类的方法
    • method_exchangeImplementations 是交换方法的实现,当获取的方法来自于父类时,也会造成父类调用时被触发, 交换方法的实现,由于方法的实现来自于父类,所以实际是交换的父类的方法的实现

    相关文章

      网友评论

          本文标题:iOS Runtime之方法替换

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