前段时间公司开始禁止使用第三方sdk,这对于程序猿的我来说无疑是一次毁灭性的打击,开发时间变得无可估量了,其中分配到我名下的任务就是要仿造友盟数据统计收集这个功能,这个东西说难不难,说简单不简单,数据统计肯定要求数据的准确性,首先要完成的是统计页面使用这个模块。今天这里就说说统计页面使用这个模块的思路,同时附上代码,由于开发时间紧迫,代码的封装性简洁性不那么强,重在理解思路,没有思路就不可能实现业务逻辑。
首先要搞明白一点,数据收集的目的说白了就是更加深入了解用户习惯和用户行为,通过分析这些数据能更好的理解用户意图,从而改进提高产品的质量。大数据的时代,没有统计数据这块的产品肯定会落伍。
下面直接正题不废话,进入页面使用统计这个模块正题。
需求:用户每进入一个页面就需要对该次操作进行记录,包括页面(ViewController)的title, 上一个页面(LastViewController)的title,进入该页面的时间等等字段需要记录。
思路:首先要进行准确的统计,必须要先了解控制器(ViewController)的生命周期,生命周期有按照以下顺序进行调用:
当一个视图控制器被创建,并在屏幕上显示的时候。 代码的执行顺序
1、 alloc 创建对象,分配空间
2、init (initWithNibName) 初始化对象,初始化数据
3、loadView 从nib载入视图 ,通常这一步不需要去干涉。除非你没有使用xib文件创建视图
4、viewDidLoad 载入完成,可以进行自定义数据以及动态创建其他控件
5、viewWillAppear 视图将出现在屏幕之前,马上这个视图就会被展现在屏幕上了
6、viewDidAppear 视图已在屏幕上渲染完成
当一个视图被移除屏幕并且销毁的时候的执行顺序,这个顺序差不多和上面的相反
1、viewWillDisappear 视图将被从屏幕上移除之前执行
2、viewDidDisappear 视图已经被从屏幕上移除,用户看不到这个视图了
3、dealloc 视图被销毁,此处需要对你在init和viewDidLoad中创建的对象进行释放
那么问题就来了,我们需要对页面进行准确的统计,那么我们记录控制器被使用的方法必须写在唯一的系统API里面,那么首先就可以把viewWillAppear、viewWillDisappear 排除在外,明显这两个方法不符合我们的需求,因为控制器无论调用viewDidLoad 还是从上级页面调popViewControllerAnimated 这个方法,当前页面都会调用viewWillAppear这个函数,这就会导致我们统计页面的数据不准确。那么再回到上面几个方法里看,alloc init更不可能,这些方法只是让控制器在系统中分配内存并初始化,并不适合写入我们记录控制器的操作,至于loadview这个方法也不太现实,特别是纯代码构建视图的童鞋,更加要排除在外,那么只剩下viewDidLoad、viewDidDisappear、dealloc这三个方法适合我们去写入我们想要记录控制器被使用记录的代码了,这里我选择了viewDidLoad、dealloc这两个方法里做文章,原因很简单,这两个函数在整个控制器的生命周期百分百的只会被调用一次,不可能再多,那就满足了我们的需求了。好了,首先我们明确了我们该在哪个系统方法里去做文章了,接下来就是解决怎么做文章的问题了。
每个控制器都要统计被使用的次数,那么这里我们要尽可能的去把通用的东西提炼出来,确保效率。我们首先统计每个控制器被初始化时候的数据(生成这个页面的数据记录),这里我创建了一个管理类,当然是个单例,代码如下
PageCollectionManger.h
@interface PageCollectionManger : NSObject
- (void)viewControllerDidLoadByController:(BaseViewController *)currentController andPageName:(NSString*)pageName;
+(instancetype)sharedInstance;
@end
PageCollectionManger.m
@implementation PageCollectionManger {
}
static PageCollectionManger *manger = nil;
+(instancetype)sharedInstance {
return [[self alloc] init];
}
- (instancetype)init {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manger = [super init];
});
return manger;
}
+(instancetype)allocWithZone:(struct _NSZone *)zone{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
manger = [super allocWithZone:zone];
});
return manger;
}
- (void)viewControllerDidLoadByController:(BaseViewController *)currentController andPageName:(NSString*)pageName{
NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
for (UIViewController *controller in currentController.navigationController.viewControllers) {
[array addObject:controller];
}
NSString *str = @"";
UIViewController *vc = [[UIViewController alloc] init];
if (array.count>=2) {
vc = array[array.count-2];
str = vc.title;
}
NSLog(@“lastPage—%@“,str);
NSLog(@“currentPage—%@“,currentController.title);
}
@end
然后我们只需要在每个控制器的viewDidLoad方法里面调一句代码就可以记录当前控制器和上级控制器了,代码如下:
[[PageCollectionManger sharedInstance] viewControllerDidLoadByController:self andPageName:self.tilte];
注意:这句代码要在你设置完控制器的title后调用!!!!
到这里我们的工作只完成了一半,我们不能只管生,不管死。
关于控制器的销毁怎么去记录:一般我们在项目里头, 所有的控制器都会继承自一个BaseViewController这玩意,那么当然我们要在这个父类里去做手脚了,下面我把我写的BaseViewController的代码粘贴出来,这里只需要在delloc方法里去做文章,因为每一个控制器的销毁意味着返回到上一级的控制器了,所以对于上一级控制器来说,当前控制器就是LastViewController,而上一级控制器只需要遍历当前所有的控制器取索引为array.count-2即可。
BaseViewController.m
- (void)dealloc{
//pop的逻辑
[self gogogo];
NSLog(@"返回上一个页面");
}
- (void)gogogo {
NSMutableArray *array = [NSMutableArray arrayWithCapacity:0];
for (UIViewController *controller in self.navigationController.viewControllers) {
[array addObject:controller];
}
NSString *str = @"";
UIViewController *vc = [[UIViewController alloc] init];
if (array.count>=2) {
vc = array[array.count-2];
str = vc.title;
}
NSLog(@"lastPage---%@",self.title);
NSLog(@"currentPage----%@",str);
}
因为每次控制器在调用popViewControllerAnimated之后就会调用dealloc,也可以理解为当返回上一级页面时我就把上一级页面的currentpage和lastpage两个字段给记录下来。
到这里 我们就能完整的保证了每个页面在用户的使用中显示一次记录一次,保证了准确性,时间有限,肯定有不少疏漏之处,这仅仅是给和我一样遭遇的童鞋一个思路,如有错误请指正。
网友评论