序言
实现
调用Aspects框架的aspect_hookSelector
方法对方法进行 hook
[BaseViewController aspect_hookSelector:@selector(viewDidLoad) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo) {
BaseViewController *vc = aspectInfo.instance;
if (!vc.dataModel) vc.dataModel = [DataCubeModel new];
// 未设置别名使用控制器名
if (vc.dataModel.alias_page == nil) {
NSDictionary *dict = [DataCubeTracker sharedIntance].cubeMapp;
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
__block BOOL isContain = NO;
if ([obj containsString:@","]) {
NSArray *objArr = [obj componentsSeparatedByString:@","];
[objArr enumerateObjectsUsingBlock:^(NSString *obj1, NSUInteger idx, BOOL *stop1) {
if ([obj1 isEqualToString:NSStringFromClass([vc class])]) {
isContain = YES;
*stop1 = YES;
}
}];
}else{
if ([obj isEqualToString:NSStringFromClass([vc class])]) {
isContain = YES;
}
}
if (isContain) {
if ([key containsString:@"|"]) {
key = [[key componentsSeparatedByString:@"|"] firstObject];
}
vc.dataModel.alias_page = key;
*stop = YES;
}
}];
}
if (vc.dataModel.alias_page == nil) {
vc.dataModel.alias_page = NSStringFromClass([vc class]);
}
} error:NULL];
简单解读一下上述方法
- 先定义一个 VC 的基类为
BaseViewController
,封装一个模型对象DataCubeModel
,里面定义一些变量名,比如上一页 VC 名称,当前页 VC 名称等。基类定义该变量,如果当前控制器的别名为空,则根据之前定义好的给该控制器取一个名称。
- 先定义一个 VC 的基类为
事先定义一个字典,里面定义了当前工程所有控制器所对应的别名。
"NewPasswordPage|重置密码": "ChangePasswordViewController",
"CategoryIndexPage|分类页": "CategoryViewController",
二 对viewWillDisappear:
,viewDidDisappear:
方法进行 hook,然后使用全局变量保存即将要离开页面的相关数据
-
UITabBarController
类型 VC 处理
[BaseViewController aspect_hookSelector:@selector(viewWillDisappear:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo ,BOOL animated){
BaseViewController *vc = aspectInfo.instance;
UITabBarController *presentVC = (UITabBarController *)vc.presentingViewController;
if(presentVC){//只有modal出来的才会走
[CSLibs sharedInstance].tmpPageAlias = vc.dataModel.alias_page;
[CSLibs sharedInstance].tmpVisitPage = vc.dataModel.visit_page;
}
} error:NULL];
-
BaseViewController
VC 处理
[BaseViewController aspect_hookSelector:@selector(viewDidDisappear:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo ,BOOL animated){
BaseViewController *vc = aspectInfo.instance;
//只走一次
if (![CSLibs sharedInstance].tmpPageAlias) {
[CSLibs sharedInstance].tmpPageAlias = vc.dataModel.alias_page;
}
if (![CSLibs sharedInstance].tmpVisitPage) {
[CSLibs sharedInstance].tmpVisitPage = vc.dataModel.visit_page;
if (![CSLibs sharedInstance].tmpVisitPage) {
[CSLibs sharedInstance].tmpVisitPage = vc.dataModel.alias_page;
}
}
} error:NULL];
三 对viewDidAppear:
方法进行 hook,然后对相关数据进行赋值操作
[BaseViewController aspect_hookSelector:@selector(viewDidAppear:) withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo ,BOOL animated){
BaseViewController *vc = aspectInfo.instance;
UITabBarController *presentVC = (UITabBarController *)vc.presentingViewController;
NSString *aliasPrevPage = [[CSLibs sharedInstance].tmpPageAlias copy];
NSString *prevPage = [[CSLibs sharedInstance].tmpVisitPage copy];
if(presentVC){//只有modal出来的才会走
UINavigationController *navi;
if ([presentVC isKindOfClass:[UITabBarController class]]) {
navi = [presentVC selectedViewController];
} else if([presentVC isKindOfClass:[UINavigationController class]]){
navi = (UINavigationController *)presentVC;
}
NSArray *viewcontrollers = navi.viewControllers;
BaseViewController *lastVC = nil;
if(viewcontrollers.count >= 1){
lastVC = [viewcontrollers objectAtIndex:viewcontrollers.count - 1];
}
if(lastVC && [lastVC isKindOfClass:[BaseViewController class]]){
aliasPrevPage = lastVC.dataModel.alias_page;
prevPage = lastVC.dataModel.visit_page;
}
}
vc.dataModel.alias_prev_page = aliasPrevPage;
vc.dataModel.prev_page = prevPage;
[CSLibs sharedInstance].tmpPageAlias = nil;
[CSLibs sharedInstance].tmpVisitPage = nil;
} error:NULL];
这样就将用户浏览过的页面全部都记录了下来,然后根据需要进行传值或上报相关数据即可。