@IT·前端iOS之runtime运行时

iOS runtime之swizzling

2017-08-15  本文已影响19人  秦萍健

问题一:
接手一个新的ios项目, 如何在复杂的项目结构中,快速定位当前显示的是哪个Controller, 直接打印此Controller的类名呢?

解决方法:
给UIViewController新增一个Category, 在Category的load方法里, 使用runtime的swizzling机制, 实现项目原来的viewWillAppear方法与自己新增的方法进行互换.
(如果项目中有基类(baseViewController), 可以直接在基类中打印)

代码实现:

#import "UIViewController+Swizzling.h"
#import <objc/runtime.h>
@implementation UIViewController (Swizzling)
//系统自带的加载方法
+(void)load{
    //我们只有在开发的时候才需要查看哪个viewController将出现
    //所以在release模式下就没必要进行方法的交换
#ifdef DEBUG
    //原本的viewWillAppear方法
    Method viewWillAppear = class_getInstanceMethod(self, @selector(viewWillAppear:));
    //需要替换成 能够输出日志的viewWillAppear
    Method logViewWillAppear = class_getInstanceMethod(self, @selector(logViewWillAppear:));
    //两方法进行交换
    method_exchangeImplementations(viewWillAppear, logViewWillAppear);
#endif
}

//实现自己的方法
-(void)logViewWillAppear:(BOOL)animated{
    //我的目的:
    NSString *className = NSStringFromClass([self class]);
    NSLog(@"当前控制器是:%@",className);

    //交换了方法以后, 记得原本的viewWillAppear方法也要走一遍,不然你就直接改了原来项目的代码了
    //so:调用原本的viewWillAppear:(load时已经交换了,所以如下调用)
    [self logViewWillAppear:animated];
}



问题二:
我们知道, 系统的NSMutableArray的addObject方法, 不可以用来添加nil对象, 否则会引起crash. 那么, 我们能使用swizzling对它修改, 使他即使新增了nil对象, 也不引起crash, 而且也不会"真正的"加入数组里.

代码实现:

#import "NSMutableArray+Swizzling.h"
#import <objc/runtime.h>
@implementation NSMutableArray (Swizzling)

+(void)load{
    Method system = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), @selector(addObject:));
    Method mine = class_getInstanceMethod(NSClassFromString(@"__NSArrayM"), @selector(addMineObj:));
    //交换:
    method_exchangeImplementations(system, mine);
}

//实现自己的方法
-(void)addMineObj:(id)obj{
    if (obj != nil) {
        
        //因为已经交换了, 所以实质是运行system方法
        [self addMineObj:obj];
    }
    //如果为nil, 实质并没有加进去.
}

上一篇下一篇

猜你喜欢

热点阅读