iOS面试题集合

iOS MethodSwizzled坑点

2020-02-04  本文已影响0人  Joker_King

交换类主动调用+(void)load方法

我们的MethodSwizzled在+(void)load方法中执行交换操作后,如果在其他地方在主动调用一次的话那么之前交换过的方法又会被交换回去,效果就等于是没有交换。

解决的方案就是使用单利设计模式,保证方法交换的代码只被执行一次。

交换的方法是父类的方法

如果交换的方法是父类的方法,就会导致父类调用该方法时报错,因为父类没有子类中的那个被交换的方法。
解决方案:

+ (void)lg_betterMethodSwizzlingWithClass:(Class)cls oriSEL:(SEL)oriSEL swizzledSEL:(SEL)swizzledSEL{
    
    if (!cls) NSLog(@"传入的交换类不能为空");
    Method oriMethod = class_getInstanceMethod(cls, oriSEL);
    Method swiMethod = class_getInstanceMethod(cls, swizzledSEL);
    // 尝试添加
    BOOL success = class_addMethod(cls, oriSEL, method_getImplementation(swiMethod), method_getTypeEncoding(oriMethod));
    if (success) {// 添加成功了证明自己没有,那么直接替换
        class_replaceMethod(cls, swizzledSEL, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
    } else { // 自己有直接交换
        method_exchangeImplementations(oriMethod, swiMethod);
    }
}

交换的方法不存在

如果要交换的方法不存在,那么就会导致交换失败,那么这时候我们需要在上面的基础上多增加一次判断,判断在执行方法交换之前。

+ (void)lg_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));
        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);
    }
}
上一篇下一篇

猜你喜欢

热点阅读