?????? 前段時間公司開始禁止使用第三方sdk,這對于程序猿的我來說無疑是一次毀滅性的打擊,開發(fā)時間變得無可估量了,其中分配到我名下的任務(wù)就是要仿造友盟數(shù)據(jù)統(tǒng)計收集這個功能,這個東西說難不難,說簡單不簡單,數(shù)據(jù)統(tǒng)計肯定要求數(shù)據(jù)的準確性,首先要完成的是統(tǒng)計頁面使用這個模塊。今天這里就說說統(tǒng)計頁面使用這個模塊的思路,同時附上代碼,由于開發(fā)時間緊迫,代碼的封裝性簡潔性不那么強,重在理解思路,沒有思路就不可能實現(xiàn)業(yè)務(wù)邏輯。
? ? ??? 首先要搞明白一點,數(shù)據(jù)收集的目的說白了就是更加深入了解用戶習(xí)慣和用戶行為,通過分析這些數(shù)據(jù)能更好的理解用戶意圖,從而改進提高產(chǎn)品的質(zhì)量。大數(shù)據(jù)的時代,沒有統(tǒng)計數(shù)據(jù)這塊的產(chǎn)品肯定會落伍。
???????? 下面直接正題不廢話,進入頁面使用統(tǒng)計這個模塊正題。
???????? 需求:用戶每進入一個頁面就需要對該次操作進行記錄,包括頁面(ViewController)的title, 上一個頁面(LastViewController)的title,進入該頁面的時間等等字段需要記錄。
? ? ? ? 思路:首先要進行準確的統(tǒng)計,必須要先了解控制器(ViewController)的生命周期,生命周期有按照以下順序進行調(diào)用:
當一個視圖控制器被創(chuàng)建,并在屏幕上顯示的時候。 代碼的執(zhí)行順序
1、 alloc ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 創(chuàng)建對象,分配空間
2、init (initWithNibName) 初始化對象,初始化數(shù)據(jù)
3、loadView ? ? ? ? ? ? ? ? ? ? ? ? ?從nib載入視圖 ,通常這一步不需要去干涉。除非你沒有使用xib文件創(chuàng)建視圖
4、viewDidLoad ? ? ? ? ? ? ? ? ? 載入完成,可以進行自定義數(shù)據(jù)以及動態(tài)創(chuàng)建其他控件
5、viewWillAppear ? ? ? ? ? ? ?視圖將出現(xiàn)在屏幕之前,馬上這個視圖就會被展現(xiàn)在屏幕上了
6、viewDidAppear ? ? ? ? ? ? ? 視圖已在屏幕上渲染完成
當一個視圖被移除屏幕并且銷毀的時候的執(zhí)行順序,這個順序差不多和上面的相反
1、viewWillDisappear ? ? ? ? ? ?視圖將被從屏幕上移除之前執(zhí)行
2、viewDidDisappear ? ? ? ? ? ? 視圖已經(jīng)被從屏幕上移除,用戶看不到這個視圖了
3、dealloc ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 視圖被銷毀,此處需要對你在init和viewDidLoad中創(chuàng)建的對象進行釋放
那么問題就來了,我們需要對頁面進行準確的統(tǒng)計,那么我們記錄控制器被使用的方法必須寫在唯一的系統(tǒng)API里面,那么首先就可以把viewWillAppear、viewWillDisappear 排除在外,明顯這兩個方法不符合我們的需求,因為控制器無論調(diào)用viewDidLoad 還是從上級頁面調(diào)popViewControllerAnimated 這個方法,當前頁面都會調(diào)用viewWillAppear這個函數(shù),這就會導(dǎo)致我們統(tǒng)計頁面的數(shù)據(jù)不準確。那么再回到上面幾個方法里看,alloc init更不可能,這些方法只是讓控制器在系統(tǒng)中分配內(nèi)存并初始化,并不適合寫入我們記錄控制器的操作,至于loadview這個方法也不太現(xiàn)實,特別是純代碼構(gòu)建視圖的童鞋,更加要排除在外,那么只剩下viewDidLoad、viewDidDisappear、dealloc這三個方法適合我們?nèi)懭胛覀兿胍涗浛刂破鞅皇褂糜涗浀拇a了,這里我選擇了viewDidLoad、dealloc這兩個方法里做文章,原因很簡單,這兩個函數(shù)在整個控制器的生命周期百分百的只會被調(diào)用一次,不可能再多,那就滿足了我們的需求了。好了,首先我們明確了我們該在哪個系統(tǒng)方法里去做文章了,接下來就是解決怎么做文章的問題了。
?????? 每個控制器都要統(tǒng)計被使用的次數(shù),那么這里我們要盡可能的去把通用的東西提煉出來,確保效率。我們首先統(tǒng)計每個控制器被初始化時候的數(shù)據(jù)(生成這個頁面的數(shù)據(jù)記錄),這里我創(chuàng)建了一個管理類,當然是個單例,代碼如下
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(@“l(fā)astPage—%@“,str);
NSLog(@“currentPage—%@“,currentController.title);
}
@end
然后我們只需要在每個控制器的viewDidLoad方法里面調(diào)一句代碼就可以記錄當前控制器和上級控制器了,代碼如下:
[[PageCollectionManger sharedInstance] viewControllerDidLoadByController:self andPageName:self.tilte];
注意:這句代碼要在你設(shè)置完控制器的title后調(diào)用?。。?!
到這里我們的工作只完成了一半,我們不能只管生,不管死。
關(guān)于控制器的銷毀怎么去記錄:一般我們在項目里頭, 所有的控制器都會繼承自一個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);
}
因為每次控制器在調(diào)用popViewControllerAnimated之后就會調(diào)用dealloc,也可以理解為當返回上一級頁面時我就把上一級頁面的currentpage和lastpage兩個字段給記錄下來。
到這里 我們就能完整的保證了每個頁面在用戶的使用中顯示一次記錄一次,保證了準確性,時間有限,肯定有不少疏漏之處,這僅僅是給和我一樣遭遇的童鞋一個思路,如有錯誤請指正。