標籤:bugs va_arg string ring debug模式 拼接 文章 one 類型
1.Objective-C
在使用Objective-C進行開發的過程中,為了Debug會不斷的設定列印函數。如是我們經常用的,用來測試監聽方法的實現與否:
1 NSLog(@"%s", __func__);2 NSLog(@"%s", __FUNCTION__);
需要說明的是,__func__和__FUNCTION__都是C的預定義符號,代表的含義完全相同,就是返回 類名+方法名 的字串。
注意:1.返回的字串是C語言的字串 char * 類型,注意預留位置是 "%s"。
2.兩個預定義符號前後都是兩個底線,注意不要寫成一個。
列印結果:
1 2016-11-25 09:53:05.769 RoonenSmartLifeSecondPhase[47510:1409025] -[JTSmartLifeViewController buttonDidPress:]2 2016-11-25 09:53:05.770 RoonenSmartLifeSecondPhase[47510:1409025] -[JTSmartLifeViewController buttonDidPress:]
可以看到,完全相同。
但是需要注意的一點是,我們的程式分為兩種模式:Debug和Release。具體可以在這個位置看到:
兩種模式的意義從它們的命名上就明白了:1.Debug:調試 2.Release:發布 。區別很明顯,Debug模式下自然是不考慮資源佔用以發現Bug為目的,而發布模式下自然要最大化最佳化效能。
那麼我們再回頭看列印這個函數:除錯模式下,列印自然是十分有用的;發布模式下,列印就沒什麼用了,還大量佔用系統資源。為什嗎?因為 NSLog() 這個函數,本質上就是在不停地拼接字串。很明顯我們在發布狀態下是不能列印的。
那麼我們如何去在調試狀態下讓它列印,在發布狀態下不讓它列印呢?
我們可以用下面這個宏來解決:
1 /*** 日誌 ***/2 // 若是在DEBUG模式下運行,則列印;若不是,則什麼都不做3 #ifdef DEBUG4 #define JTLog(...) NSLog(__VA_ARGS__)5 #else6 #define JTLog(...)7 #endif
其中需要注意的是:
__VA_ARGS__:總體來說就是將左邊宏中 ... 的內容原樣抄寫在右邊 __VA_ARGS__ 所在的位置。它是一個可變參數的宏,是新的C99規範中新增的。
好了,那麼上面這個宏的定義就非常清晰了。若處於 DEBUG 這個宏生效的模式下(自然也就是Debug模式),那麼調用 JTLog(...) 這個宏就與調用 NSLog(...) 完全一致;否則,調用 JTLog(...) 等於什麼都不做。我們需要列印的時候,就直接調用 JTLog(...) 來代替 NSLog(...) 就可以了。功能實現了!
等等!DEBUG這個宏是什麼意思?
我們試著 command+左鍵 這個宏,發現系統找不到這個宏所在的位置。為什麼會這樣?
其實這個宏在這個位置:
也就是 TARGETS --> Build Settings --> Apple LLVM 8.0 - Language - Modules --> Preprocessor Macros --> Debug 位置。
我們可以看到,它預設設定了一個宏 DEBUG=1。而在Release模式下是沒有這個宏的。其實這個宏就是在這裡設定的,所以系統才會找不到。同時我們也可以在這裡設定一些宏,格式就是:
Macro=Value
注意:這裡設定的宏名不可以全是小寫字母。
這樣就設定了一個其他人都找不到的宏了。並且你可以在任何地方調用它。但是我不建議這麼做,假如你在這裡定義了一堆宏,但是你同事或者接手代碼的人一個都找不到,你會被罵的-.-
就是這麼簡單。但最終還有一個問題。如何在所有的類中使用這個 JTLog(...) 呢?
對,自然就是放在 PrefixHeader.pch 中啦~具體不詳細介紹了,百度吧..
最後,我們可以同樣在 PrefixHeader.pch中聲明這樣一個宏,來快捷列印當前方法名:
1 #define JTLogFunc JTLog(@"%s", __func__);
調用的時候,分號都可以不寫了。
2.Swift
對,其實現在開始才是文章的重點。。假如懂得如何?Objective-C中自訂列印的道友,可以直接往下看;初學即Swift的道友推薦補習下Objective-C篇再搞定下面的東西,有些東西我就不重複介紹了。
Swift中與Objective-C很大的區別在於:Swift中沒有宏這個定義!如何是好?
確實,Swift中預設沒有宏這個定義方式,但其實我們還是可以自訂宏的。而且與上面的自訂宏的方式相同。
就是這個位置。
TARGETS --> Build Settings --> Swift Complier - Custom Flags --> Other Swift Flags --> DEBUG
格式 -D DEBUGSWIFT 。也就是聲明的宏之前要加一個這樣的符號 -D 。它會自動分成兩行顯示。
建議與上面Objective-C的 DEBUG 宏區分表示,以免混淆。
宏有了,具體列印怎麼寫呢?
非常簡單。聲明一個全域函數即可。
1 func JTPrint<N>(message: N) {2 3 #if DEBUGSWIFT4 print(message)
5 #endif
6 }
另外再說一句:把這個函數放在任意一個類的外面,即 class{ } 外面,就是全域函數了,全域變數也是一樣的。
或者你可以聲明一個資訊異常齊全的列印,使用預定義符添加一些其他你想要看到的資訊。比如這樣:
1 func JTPrint<N>(message: N, fileName: String = #file, methodName: String = #function, lineNumber: Int = #line){2 3 #if DEBUGSWIFT // 若是Debug模式下,則列印4 5 print("\(fileName as NSString)\n方法:\(methodName)\n行號:\(lineNumber)\n列印資訊\(message)");6 #endif7 }
列印結果那是異常的酷炫:
1 檔案名稱:Controller/SmartScene-智能情境/SmartInHomeViewController.swift2 方法:viewDidLoad()3 行號:364 列印資訊:123
Objective-C與Swift下的自訂列印函數(Debug和Release)