? ? 之前到別人的一篇博客上評論了下他的打點統(tǒng)計方法,后來很多人來問我俏蛮,,所以還是決定寫下這篇文章上遥。第一次寫博客搏屑,不喜勿噴。
? ? 關(guān)于統(tǒng)計打點粉楚,個人覺得最好的還是用面向切面編程思想(AOP)辣恋,這樣可以實現(xiàn)把我們的統(tǒng)計打點功能提出來與一批對象進行隔離亮垫,這樣與一批對象之間降低了耦合性。這里需要用到的就是Method Swizzling伟骨,如果不知道Method Swizzling饮潦,先百度一下。下面開始一一說:
一底靠、頁面(UIViewController)統(tǒng)計?
UIViewController統(tǒng)計比較簡單害晦,一般也就需要在viewWillAppear和viewWillDisappear里進行統(tǒng)計 。所以我們只需要在category中交換viewWillAppear和viewWillDisappear和兩個方法即可
#import "UIViewController+Tracking.h"
#import <objc/runtime.h>
@implementation UIViewController (Tracking)
+ (void)load {
// 交換方法viewWillAppear:
method_exchangeImplementations(class_getInstanceMethod(self, @selector(viewWillAppear:)),class_getInstanceMethod(self, @selector(tracking_viewWillAppear:)));
//交換方法viewWillDisappear:
method_exchangeImplementations(class_getInstanceMethod(self, @selector(viewWillDisappear:)), class_getInstanceMethod(self, @selector(tracking_viewWillDisappear:)));
}
- (void)tracking_viewWillAppear:(BOOL)animated {
[self tracking_viewWillAppear:animated];
//此處添加你想統(tǒng)計的打點事件
NSLog(@"當(dāng)前viewController :%@",NSStringFromClass([self class]));
}
- (void)tracking_viewWillDisappear:(BOOL)animated {
[self tracking_viewWillDisappear:animated];
//此處添加你想統(tǒng)計的打點事件
NSLog(@"當(dāng)前viewController :%@",NSStringFromClass([self class]));
}
經(jīng)過以上交換 暑中,所有的viewController就會走到自定義的tracking_viewWillAppear和tracking_viewWillDisappear方法壹瘟,就可以在注釋的地方做頁面統(tǒng)計事件了。這里統(tǒng)計建議先建立個viewController的類名或者title作為索引值鳄逾,自定義標(biāo)識為鍵值的字典或plist文件稻轨,比如@{@"homeViewController" : @"首頁"},然后就可以直接在注釋處通過NSStringFromClass([self class])獲取到viewController的類名然后索引到自定義標(biāo)識雕凹。
不過有時候殴俱,可能會出現(xiàn)一個viewController可能會復(fù)用,比如用type(或title)區(qū)分的情況枚抵,线欲,這時候,就需要你在注釋處汽摹,對self進行判斷李丰,如果是這些類,強轉(zhuǎn)后得到該類逼泣,在類名后拼接上type(或title)作為字典索引值趴泌,比如@{@"homeViewController_type1" : @"首頁", @"homeViewController_type2" : @"第二頁",}
二、按鈕(UIControl)及UIBarButtonItem點擊事件
要想統(tǒng)計UIControl點擊事件拉庶,嗜憔,首先要知道從哪地方進行方法交換,在UIControl里找到sendAction:to:forEvent:方法氏仗,吉捶,這是每次點擊都會走的方法
#import "UIControl+Tracking.h"
#import <objc/runtime.h>
@implementation UIControl (Tracking)
+ (void)load
{
method_exchangeImplementations(class_getInstanceMethod(self, @selector(sendAction:to:forEvent:)), class_getInstanceMethod(self, @selector(tracking_sendAction:to:forEvent:)));
}
- (void)tracking_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
[self tracking_sendAction:action to:target forEvent:event];
//此處添加你想統(tǒng)計的打點事件
}
就這么兩句代碼 ,然后所有的UIControl點擊事件皆尔,就會走這注釋處帚稠,我們就可以進行點擊統(tǒng)計了,在注釋這里床佳,可以獲取到的信息有action(點擊響應(yīng)的方法),control的target榄审,self(就是control本身了砌们,可以獲取title,tag等信息)還有event。簡單吧。不過這里要建的索引表就有點復(fù)雜了浪感,最常見的昔头,在同一個target(比如viewController)下,多個control指向同一方法影兽,這時我們就需要用self的tag屬性來做區(qū)分了揭斧。所以我建議拼接索引值時將target,action和tag三個值給拼起來。如@{@"homeViewController_searchAction_tag1" : @"首頁的第一個搜索按鈕" , @"homeViewController_searchAction_tag2" : @"首頁的第二個搜索按鈕"}
UIBarButtonItem 的點擊事件也會走到- (void)tracking_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event方法這峻堰,只是target變成了UIBarButtonItem讹开,所以我們需要到這方法里,對target進行判斷
- (void)tracking_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event
{
[self tracking_sendAction:action to:target forEvent:event];
if ([target isKindOfClass:[UIBarButtonItem class]]) {
UIBarButtonItem *item = (UIBarButtonItem *)target;
// 在此拼接NSStringFromClass([item.target class])和NSStringFromSelector(item.action)]]
}else {
//此處添加你想統(tǒng)計的打點事件
// 在此拼接將NSStringFromClass([target class]) ,NSStringFromSelector(action)和tag三個值給拼起來
}
}
三捐名、UITableView的cell點擊事件
UITableView的點擊事件就稍微麻煩點了旦万,因為需要切面的點擊方法tableView:didSelectRowAtIndexPath:是在代理那,所以我們需要先替換設(shè)置代理方法镶蹋,獲取到代理人成艘,然后再進行切面,上代碼
#import "UITableView+Tracking.h"
#import <objc/runtime.h>
#import <objc/message.h>
@implementation UITableView (Tracking)
+ (void)load{? ?
?//交換實現(xiàn)setDelegate,獲取到代理人? ? method_exchangeImplementations(class_getInstanceMethod(self, @selector(setDelegate:)), class_getInstanceMethod(self, @selector(tracking_setDelegate:)));
}
- (void)tracking_setDelegate:(id)delegate
{
[self tracking_setDelegate:delegate];
Class class = [delegate class];
// 在代理人這先添加用于實現(xiàn)統(tǒng)計的方法贺归,然后和交換原先的點擊方法
if (class_addMethod(class, NSSelectorFromString(@"tracking_didSelectRowAtIndexPath"), (IMP)tracking_didSelectRowAtIndexPath, "v@:@@")) {
Method dis_originalMethod = class_getInstanceMethod(class, NSSelectorFromString(@"tracking_didSelectRowAtIndexPath"));
Method dis_swizzledMethod = class_getInstanceMethod(class, @selector(tableView:didSelectRowAtIndexPath:));
//交換實現(xiàn)
method_exchangeImplementations(dis_originalMethod, dis_swizzledMethod);
}
}
void tracking_didSelectRowAtIndexPath(id self, SEL _cmd, id tableView, id indexpath)
{
SEL selector = NSSelectorFromString(@"tracking_didSelectRowAtIndexPath");
((void(*)(id, SEL,id, id))objc_msgSend)(self, selector, tableView, indexpath);
//此處添加你想統(tǒng)計的打點事件
}
@end
這里會因為要將代理人的方法進行切面淆两,所以這需要給代理人通過class_addMethod這方式動態(tài)的添加方法。至于為什么要判斷是因為拂酣,只能第一次添加時才進行交換秋冰,不判斷的話,多設(shè)置幾次delegate踱葛,就會多交換幾次丹莲,偶數(shù)次就會還原了,不會進入設(shè)置好的統(tǒng)計打點方法尸诽。至于為什么要寫成((void(*)(id, SEL,id, id))objc_msgSend)甥材,是為什么兼容ios的多版本問題。最后的統(tǒng)計和上面的也差不多了性含,都是建立字典洲赵,只不過已知信息換成了(id self, SEL _cmd, id tableView, id indexpath),里面self也就是delegate商蕴,
四叠萍,UICollectionView的點擊統(tǒng)計
UICollectionView的點擊統(tǒng)計和UITableView的點擊統(tǒng)計原理差不多,都是先交換setDelegate:這里就不展示了绪商,想要看直接去我的github上下載就可以了苛谷,下載地址https://github.com/363128432/ActionTracking/tree/master/Tracking
最后,很多人還問格郁,能不能自動生成索引字典的key腹殿,独悴,這我只想到了進入每個頁面時自動寫成plist文件的key,最后導(dǎo)出成锣尉,刻炒,但是需要人一個頁面一個頁面創(chuàng)建,如果有誰知道怎么一開始在main函數(shù)獲取所有的類自沧,歡迎聯(lián)系我坟奥,,解決這一問題拇厢。