iOS Runtime 方法交换

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        SEL originSEL = @selector(viewWillAppear:);
        SEL swizzleSEL = @selector(xx_viewWillAppear:);
        
        Method originMethod = class_getInstanceMethod([self class], originSEL);
        Method swizzleMethod = class_getInstanceMethod([self class], swizzleSEL);
        
        /*给原来的方法添加实现
         如果添加成功则说明该类中没有实现原方法, 同时也为该原方法添加了实现(本例中的`viewWillAppear:`方法不存在这个问题)
         如果添加失败, 说明该类中已经有了原方法的实现, 直接交换方法即可
         */
        BOOL addSucceed = class_addMethod([self class], originSEL, method_getImplementation(swizzleMethod), method_getTypeEncoding(swizzleMethod));
        if (addSucceed) {
            //添加成功
            class_replaceMethod([self class], swizzleSEL, method_getImplementation(originMethod), method_getTypeEncoding(originMethod));
        }else {
            //添加失败
            method_exchangeImplementations(originMethod, swizzleMethod);
        }
    });
}

- (void)xx_viewWillAppear:(BOOL)animated {
    //这里调用自己不会造成死循环, 看似是调用自己, 实则调用的是`viewWillAppear:`的实现
    [self xx_viewWillAppear:animated];
    NSLog(@"xx_viewWillAppear");
}
image.png
  1. 之所以选在load方法中去实现, 是因为load在文件加载的时候就会被调用, 甚至早于main函数, 这样不会出现原方法被调用的时候, 还没交换的情况

  2. dispatch_once_t就是保证这段代码只执行一次

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容