iOS面试专题

oc中的方法hook(Method Swizzling)

2020-06-26  本文已影响0人  三国韩信

Method Swizzling 的坑

hook方法一般在load方法里执行,那么load方法的调用顺序也会影响到。load方法的顺序:父类->子类->子类的分类->父类的分类(不走方法的查找流程)

1、load方法要用dispatch_once包裹,保证只运行一次。单利设计

2、我们在交换系统方法的时候,有些类不能用类名直接去交换,它们是类簇的情况,比如NSArray、NSMutablArray等。它们要用"__NSArrayI"去交换方法。

3、hook子类没有实现的(父类实现了)的方法。

4、交换根本没有实现的方法。 顾名思义就是说交换的方法,不仅本类未实现,其父类中也没有实现,那么交换就没有成功,那么就会出现自己调用自己的情况,出现死循环。

+ (void)bestMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
    if (!cls) NSLog(@"传入的交换类不能为空");
    Method oriMethod = class_getInstanceMethod(cls, oriSEL);
    Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
    if (!oriMethod) {
        class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
        // IMP指向了一个空的block方法(空IMP)
        method_setImplementation(swiMethod, imp_implementationWithBlock(^(id self, SEL _cmd){ }));
    }
 
    BOOL didAddMethod = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(swiMethod));
    if (didAddMethod) {
        class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
    }else{
        method_exchangeImplementations(oriMethod, swiMethod);
    }

5、当子类和父类都同时hook同一个方法的时候,那么情况就更复杂了

6、父类的hook的swizzling selector方法和子类的swizzling selector同名的时候,会出现unrecognized selector 异常或死循环的情况。

总结: 对于项目中我们自己写method swizzling,最好就是子类和父类都实现了要hook的方法,哪怕是空实现也要,父类和子类的swizzling selector最好不要一样的命名。最好先Super类后Child类。RSSwizzle 是被很多人推荐框架,它用很复杂的方式解决了 What are the Dangers of Method Swizzling in Objective C? 中提到的一系列问题。不过引入它还是有一些成本的,只有在穷举的那些极端特殊情况下才使用它,文章开头处的交互方案代码已经能 Cover 到大部分情况了。

最后安利一篇博文,在这篇文章里杨萧玉大神就OC的Method Swizzling 的各种情况做了很详细的分析,相当的棒,膜拜大神!==> Objective-C-Method-Swizzling

上一篇 下一篇

猜你喜欢

热点阅读