iOS Runtime运行时机制的正确使用姿势

Runtime运行时机制在项目中的实际使用:

相信很多人都有过这样的经历,就是当我们接手一个项目时,若要修复某个BUG或是查看某某功能是如何实现的,特别是大项目,再加上对项目的业务逻辑不熟悉、对项目的设计架构不熟悉的情况下,我们往往感到无从下手,或是需要花一定的时间才能找出对应的类。

这篇博客就是为了需要让人感到蛋疼的问题而写的。

解决方案
给UIViewContoller建立一个分类,利用分类的特性,可以很好很方便地进行管理。类中原有的方法保持执行,还能扩展打印信息。

别忘了import < objc/runtime.h>

//load方法会在类第一次加载的时候被调用,调用的时间比较靠前。当类或分类被添加进运行时机制时就会调用。
//适合在这个方法里做方法交换,方法交换应该被保证在程序中只会执行一次。
+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        Class selfClass = [self class];
        SEL oriSel = @selector(viewWillAppear:);
        Method oriMethod = class_getInstanceMethod(selfClass, oriSel);

        //需要替换成能够输出日志的viewWillAppear
        SEL currSel = @selector(logViewWillAppear:);
        Method currMethod = class_getInstanceMethod(selfClass, currSel);

        BOOL addSuccess = class_addMethod(selfClass,
                                          oriSel,
                                          method_getImplementation(currMethod),
                                          method_getTypeEncoding(currMethod)
                                          );
        if (addSuccess) {
            class_replaceMethod(selfClass, currSel, method_getImplementation(oriMethod), method_getTypeEncoding(oriMethod));
        }
        else {
            //利用运行时机制,对方法进行调包交换。
            method_exchangeImplementations(oriMethod, currMethod);
        }
    });
}

- (void)logViewWillAppear:(BOOL)animated {
    NSString *classNameString = NSStringFromClass([self class]);
    //此处进行过滤打印
    if (![classNameString hasPrefix:@"Base"] && ![classNameString hasPrefix:@"Main"]) {
        NSLog(@"当前控制器为:%@", classNameString);
    }

    //实际调用的是viewWillAppear
    [self logViewWillAppear:animated];
}

@end

猜你喜欢

转载自blog.csdn.net/jingfa1993/article/details/72650238