一、先拋出問題
1.由于我們的工程項(xiàng)目較大,人員流動(dòng)也比較大贿条,項(xiàng)目整體管理不夠緊湊,可能時(shí)不時(shí)會(huì)接手別人的工
作但連是主控制器都不知道是哪個(gè)雹仿,那我們能不能在每個(gè)vc加載時(shí)都打印出vc的名字以便我們直接
找到這個(gè)類呢,也許你會(huì)說在每個(gè)viewdidload里寫一個(gè)log整以,但我們的項(xiàng)目中現(xiàn)在大約有
幾千個(gè)文件胧辽,上百個(gè)vc,一個(gè)一個(gè)來添加當(dāng)然不是一個(gè)好辦法公黑。
2.我想記錄用戶進(jìn)入每個(gè)頁面的紀(jì)錄來判斷用戶的愛好邑商,但不想去調(diào)試修改每個(gè)vc的代碼
二、解決方法
每個(gè)vc加載時(shí)都會(huì)走load這個(gè)方法凡蚜,我們可以建個(gè)全局的pch文件并寫個(gè)vc的category類人断,每當(dāng)
執(zhí)行l(wèi)oad方法時(shí)我們通過交換viewdidload 和自定義的LogViewDidLoad(用于輸出日志和
上傳用戶點(diǎn)擊事件)來達(dá)到我們想要的效果
三、具體實(shí)施
首先朝蜘、建一個(gè)viewcontroller的category類恶迈,我這隨手起了個(gè)名字UIViewController+LogStatistics.m
其次、在load方法中交換viewdidload 和自定義的LogViewDidLoad(用于log輸出當(dāng)前vc信息)
+(void)load{
[super load];
Method defaulTMethod = class_getInstanceMethod([self class], @selector(viewDidLoad));
Method changeMethod = class_getInstanceMethod([self class], @selector(LogViewDidLoad));
/**
* 我們在這里使用class_addMethod()函數(shù)對Method Swizzling做了一層驗(yàn)證谱醇,如果self沒有實(shí)現(xiàn)被交換的方法暇仲,會(huì)導(dǎo)致失敗。
* 而且self沒有交換的方法實(shí)現(xiàn)枣抱,但是父類有這個(gè)方法熔吗,這樣就會(huì)調(diào)用父類的方法,結(jié)果就不是我們想要的結(jié)果了佳晶。
* 所以我們在這里通過class_addMethod()的驗(yàn)證桅狠,如果self實(shí)現(xiàn)了這個(gè)方法,class_addMethod()函數(shù)將會(huì)返回NO轿秧,我們就可以對其進(jìn)行交換了中跌。
*/
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(@"用戶點(diǎn)擊了%@vc\n",className);
//上傳服務(wù)器用戶的點(diǎn)擊事件
}
[self LogViewDidLoad];
}
再次,為了讓每個(gè)vc都能執(zhí)行category里的方法菇篡,我們需要建一個(gè)pch文件放到prefix headder中
至此漩符,大功告成,快來跑跑看驱还,是不是每個(gè)vc都可以直接打印出當(dāng)前vc的信息了
當(dāng)然交換方法不僅僅可以這樣用嗜暴,下章來通過runtime交換method的方法實(shí)現(xiàn)一個(gè)防止整個(gè)項(xiàng)目中數(shù)組越界的category