在iOS開(kāi)發(fā)過(guò)程中,我們經(jīng)常要用到NSLog來(lái)打印一些調(diào)試信息,而且一般是習(xí)慣性的大量使用,在模擬器上運(yùn)行可能沒(méi)有感覺(jué)到什么,但是在真機(jī)上,NSLog的輸出還是比較消耗系統(tǒng)資源的,而且輸出的數(shù)據(jù)有時(shí)也可能會(huì)暴露出App中的某些數(shù)據(jù),所以發(fā)布正式版時(shí)需要把這些輸出全部屏蔽掉。
我們可以在發(fā)release包之前將這些NSLog統(tǒng)統(tǒng)注釋掉,但是如果是大量使用,就有些太過(guò)麻煩,而且下次開(kāi)發(fā)時(shí),又需要將注釋分別打開(kāi)繼續(xù)使用,這樣做著實(shí)無(wú)趣。下面列舉兩種方式解決:
1.通過(guò)DEBUG條件編譯全局控制
因?yàn)槭侨挚刂?,首先?chuàng)建pch文件,具體方法較為簡(jiǎn)單,不過(guò)在Xcode6之后注意綁定pch文件的相對(duì)路徑,
設(shè)置pch戳這里,創(chuàng)建好之后,在pch文件中添加下列代碼:
#ifdef DEBUG
#define AllLog(fmt, ...) NSLog((@"[文件名:%s]\n" "[函數(shù)名:%s]\n" "[行號(hào):%d] \n" fmt), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#define DeBugLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#define NSLog(...) NSLog(__VA_ARGS__);
#define MyNSLog(FORMAT, ...) fprintf(stderr,"[%s]:[line %d行] %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#else
#define AllLog(...)
#define DeBugLog(...)
#define NSLog(...)
#define MyNSLog(FORMAT, ...)
#endif
上述代碼中詳細(xì)列舉了四種較為常用的NSLog的封裝,一些事參考了網(wǎng)友的寫法,已做實(shí)際驗(yàn)證。
補(bǔ)充:
1)VA_ARGS是一個(gè)可變參數(shù)的宏,很少人知道這個(gè)宏,這個(gè)可變參數(shù)的宏是新的C99規(guī)范中新增的,目前似乎只有g(shù)cc支持(VC6.0的編譯器不支持)。宏前面加上##的作用在于,當(dāng)可變參數(shù)的個(gè)數(shù)為0時(shí),這里的##起到把前面多余的","去掉的作用,否則會(huì)編譯出錯(cuò), 你可以試試。
2)FILE宏在預(yù)編譯時(shí)會(huì)替換成當(dāng)前的源文件名
3)LINE宏在預(yù)編譯時(shí)會(huì)替換成當(dāng)前的行號(hào)
4)FUNCTION宏在預(yù)編譯時(shí)會(huì)替換成當(dāng)前的函數(shù)名稱
下一步是Debug和Release環(huán)境的設(shè)置:
1."Target > Build Settings > Preprocessor Macros > Debug" 里有一個(gè)"DEBUG=1",這保證了我們的條件編譯的"#if"可以編譯。如果沒(méi)有,請(qǐng)自行添加,注意和代碼中的#if后面的字段保持一致。

2.環(huán)境配置見(jiàn)下圖,通過(guò)切換Debug和Release,可以控制當(dāng)前工程的編譯環(huán)境,當(dāng)在release環(huán)境下時(shí),pch預(yù)編譯的NSLog相關(guān)函數(shù)執(zhí)行是無(wú)效的。


2.通過(guò)自定義條件編譯條件全局控制
1.首先自定義全局環(huán)境條件編譯控制字段
/**
*? 工程全局環(huán)境控制
*
*? 0:開(kāi)發(fā)環(huán)境? 1:發(fā)布環(huán)境? 2:測(cè)試環(huán)境
*/
#define MY_PROJECT_GLOBAL_CONTROL 0
上面的0、1、2看個(gè)人習(xí)慣,只要分得清楚各種環(huán)境就行。具體工程的編譯環(huán)境當(dāng)然也不局限于上述三類。
在開(kāi)發(fā)或上線時(shí),只要記得修改上述的值以對(duì)應(yīng)于相應(yīng)的環(huán)境就行,當(dāng)然最好是工程有對(duì)應(yīng)的幾個(gè)target,這樣也就可分別設(shè)置,分別使用,不會(huì)混淆了。
2.同方法1一樣,添加下面的代碼:
#if (MY_PROJECT_GLOBAL_CONTROL == 0)
#define AllLog(fmt, ...) NSLog((@"[文件名:%s]\n" "[函數(shù)名:%s]\n" "[行號(hào):%d] \n" fmt), __FILE__, __FUNCTION__, __LINE__, ##__VA_ARGS__);
#define DeBugLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#define NSLog(...) NSLog(__VA_ARGS__);
#define MyNSLog(FORMAT, ...) fprintf(stderr,"[%s]:[line %d行] %s\n",[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], __LINE__, [[NSString stringWithFormat:FORMAT, ##__VA_ARGS__] UTF8String]);
#elif (MY_PROJECT_GLOBAL_CONTROL == 1)
#define AllLog(...)
#define DeBugLog(...)
#define NSLog(...)
#define MyNSLog(FORMAT, ...)
#endif
上述省略了測(cè)試環(huán)境,測(cè)試同開(kāi)發(fā)即可。
這種方式較1更為靈活。對(duì)應(yīng)的條件編譯當(dāng)然也不僅僅局限于NSLog,還有NSAssert或者是對(duì)應(yīng)環(huán)境的接口等的設(shè)置。
原文: