美文网首页
iOS Method Swizzling

iOS Method Swizzling

作者: iOS_Ru | 来源:发表于2020-04-03 17:13 被阅读0次

标准的写法


+ (void)load {
    Method oldM = class_getInstanceMethod([self class], @selector(test));
    Method newM = class_getInstanceMethod([self class], @selector(test_new));
    
    IMP oldIMP = method_getImplementation(oldM);
    IMP newIMP = method_getImplementation(newM);
    
    BOOL isAddSucceed = class_addMethod([self class], @selector(test), newIMP, method_getTypeEncoding(newM));
    if (isAddSucceed) {
        class_replaceMethod([self class], @selector(test_new), oldIMP, method_getTypeEncoding(oldM));
    }else {
        method_exchangeImplementations(oldM, newM);
    }
}

好多同学很奇怪为啥要加个 class_addMethod方法

1.打个比方 父类 Person 子类Son
条件:
如果 test方法 只在父类Person只实现,如果子类不实现test
不调用 class_addMethod 方法。
影响:
[son test]; 调用OK 一点问题都没有
但是如果是 [person test]; 就会调用到 son的实现的new_test;
显示不符合逻辑了 这样会把父类Person搞的很坑。
2.防止父类 Person 跟子类 Son 都没有实现test方法 那直接method_exchangeImplementations 实现后 会崩溃

其实更加严禁的方法应该这么写


+ (void)load {
    Method oldM = class_getInstanceMethod([self class], @selector(test));
    Method newM = class_getInstanceMethod([self class], @selector(test_new));
    
    IMP oldIMP = method_getImplementation(oldM);
    IMP newIMP = method_getImplementation(newM);
    
    BOOL isAddSucceed = class_addMethod([self class], @selector(test), newIMP, method_getTypeEncoding(newM));
    if (isAddSucceed) {
        // 如果 class_addMethod 成功了,说明之前 fromClass 里并不存在 originSelector,所以要用一个空的方法代替它,以避免 class_replaceMethod 后,后续 toClass 的这个方法被调用时可能会 crash
        oldIMP = oldIMP ?: imp_implementationWithBlock(^(id selfObject) {});
         const char *oldTypeEncoding = method_getTypeEncoding(oldM) ?: "v@:";
        class_replaceMethod([self class], @selector(test_new), oldIMP, oldTypeEncoding);
    }else {
         method_exchangeImplementations(oldM, newM);
    }

}

相关文章

网友评论

      本文标题:iOS Method Swizzling

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