一、先抛出问题
1.由于我们的工程项目较大,人员流动也比较大,项目整体管理不够紧凑,可能时不时会接手别人的工
作但连是主控制器都不知道是哪个,那我们能不能在每个vc加载时都打印出vc的名字以便我们直接
找到这个类呢,也许你会说在每个viewdidload里写一个log,但我们的项目中现在大约有
几千个文件,上百个vc,一个一个来添加当然不是一个好办法。
2.我想记录用户进入每个页面的纪录来判断用户的爱好,但不想去调试修改每个vc的代码
二、解决方法
每个vc加载时都会走load这个方法,我们可以建个全局的pch文件并写个vc的category类,每当
执行load方法时我们通过交换viewdidload 和自定义的LogViewDidLoad(用于输出日志和
上传用户点击事件)来达到我们想要的效果
三、具体实施
首先、建一个viewcontroller的category类,我这随手起了个名字UIViewController+LogStatistics.m
其次、在load方法中交换viewdidload 和自定义的LogViewDidLoad(用于log输出当前vc信息)
+(void)load{
[super load];
Method defaulTMethod = class_getInstanceMethod([self class], @selector(viewDidLoad));
Method changeMethod = class_getInstanceMethod([self class], @selector(LogViewDidLoad));
/**
* 我们在这里使用class_addMethod()函数对Method Swizzling做了一层验证,如果self没有实现被交换的方法,会导致失败。
* 而且self没有交换的方法实现,但是父类有这个方法,这样就会调用父类的方法,结果就不是我们想要的结果了。
* 所以我们在这里通过class_addMethod()的验证,如果self实现了这个方法,class_addMethod()函数将会返回NO,我们就可以对其进行交换了。
*/
if (!class_addMethod([self class], @selector(viewDidLoad), method_getImplementation(changeMethod), method_getTypeEncoding(changeMethod))) {
method_exchangeImplementations(defaulTMethod,changeMethod);
}
}
- (void)LogViewDidLoad{
NSString *className = [NSString stringWithFormat:@"%@",[self class]];
if (![className containsString:@"UI"]) {
NSLog(@"用户点击了%@vc\n",className);
//上传服务器用户的点击事件
}
[self LogViewDidLoad];
}
再次,为了让每个vc都能执行category里的方法,我们需要建一个pch文件放到prefix headder中
至此,大功告成,快来跑跑看,是不是每个vc都可以直接打印出当前vc的信息了
当然交换方法不仅仅可以这样用,下章来通过runtime交换method的方法实现一个防止整个项目中数组越界的category