在iOS開發過程中,我們經常要用到NSLog來打印一些調試信息,而且一般是習慣性的大量使用,在模擬器上運行可能沒有感覺到什么,但是在真機上,這些NSLog的輸出還是比較消耗系統資源的,而且輸出的數據有時也可能會暴露出App中的某些私密數據,所以發布正式版時需要把這些輸出全部屏蔽掉。
我們可以在發release包之前將這些NSLog統統注釋掉,但是如果是大量使用,就有些太過麻煩,而且下次開發時,又需要將注釋分別打開繼續使用,這樣做著實無趣。
下面列舉兩種較為優雅的方式解決:
1.通過DEBUG條件編譯全局控制
因為是全局控制,首先創建pch文件,具體方法較為簡單,不過在Xcode6之后注意綁定pch文件的相對路徑,這里不再贅述。
創建好之后,在pch文件中添加下列代碼:
#ifdef DEBUG
#define DLog(fmt, ...) NSLog((@"[文件名:%s]\n" "[函數名:%s]\n" "[行號:%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 DLog(...)
#define DeBugLog(...)
#define NSLog(...)
#define MyNSLog(FORMAT, ...)
#endif
上述代碼中詳細列舉了四種較為常用的NSLog的封裝,一些事參考了網友的寫法,已做實際驗證。
補充:
1) VA_ARGS 是一個可變參數的宏,很少人知道這個宏,這個可變參數的宏是新的C99規范中新增的,目前似乎只有gcc支持(VC6.0的編譯器不支持)。宏前面加上##的作用在于,當可變參數的個數為0時,這里的##起到把前面多余的","去掉的作用,否則會編譯出錯, 你可以試試。
2) FILE 宏在預編譯時會替換成當前的源文件名
3) LINE宏在預編譯時會替換成當前的行號
4) FUNCTION宏在預編譯時會替換成當前的函數名稱
接下來是DEBUG和release環境的設置:
- 1."Target > Build Settings > Preprocessor Macros > Debug" 里有一個"DEBUG=1",這保證了我們的條件編譯的"#if"可以編譯。如果沒有,請自行添加,注意和代碼中的#if后面的字段保持一致。
-
2.環境配置見下圖,通過切換Debug和Release,可以控制當前工程的編譯環境,當在release環境下時,pch預編譯的NSLog相關函數執行是無效的。
2.通過自定義條件編譯條件全局控制
這是個人較為偏愛的一種方式,感覺比較靈活。同樣在pch文件中添加下面的代碼。
- 1.首先自定義全局環境條件編譯控制字段
/**
* 工程全局環境控制
*
* 0:開發環境 1:發布環境 2:測試環境
*/
#define MY_PROJECT_GLOBAL_CONTROL 0
上面的0、1、2看個人習慣,只要分得清楚各種環境就行。具體工程的編譯環境當然也不局限于上述三類。
在開發或上線時,只要記得修改上述的值以對應于相應的環境就行,當然最好是工程有對應的幾個target,這樣也就可分別設置,分別使用,不會混淆了。
- 2.同方法1一樣,添加下面的代碼:
#if (MY_PROJECT_GLOBAL_CONTROL == 0)
#define DLog(fmt, ...) NSLog((@"[文件名:%s]\n" "[函數名:%s]\n" "[行號:%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 DLog(...)
#define DeBugLog(...)
#define NSLog(...)
#define MyNSLog(FORMAT, ...)
#endif
上述省略了測試環境,測試同開發即可。
這種方式較1更為靈活。對應的條件編譯當然也不僅僅局限于NSLog,還有NSAssert或者是對應環境的接口等的設置。
相關Demo已經上傳至GitHub,可自行下載參考。
參考文章:
1.在ios iphone編程中使用封裝的NSLog來打印調試信息
2.IOS開發之NSLog使用技巧
3.iOS開發中那些高效常用的宏<推薦>