關于NSLog
log 用來輸出日志信息。所以 iOS 項目中中的NSLog 也是非常之多。你們項目中肯定有這種代碼
#ifdef DEBUG
# define NSLog(...) NSLog(__VA_ARGS__)
#else
# define NSLog(...)
讓log 只在DEBUG 狀態下有效。
如果只是NSLog 是不是可以單開一個線程,把NSLog 放在非主線程的線程操作會好一點???
感謝評論中的同學提醒 <code>CocoaLumberjack</code> 看了看git上的文檔才明白NSLog 為什么會引起性能為題?
通過閱讀Lumberjack性能相關,了解了一下,Lumberjack 在log方面性能的優化:
- 使用GCD, 使用GCD可以并發的寫LOG,即使系統不支持GCD 也可以使用多線程手段,合理的使用CPU
- 異步的顯示LOG信息。(顯示log信息的原理很簡單:如果是錯誤信息,就同步顯示,如果只是簡單的提示,就可以異步的顯示)。
- 為什么NSLog 會很慢。。原因如下:直接帖英文了我就
A Better NSLog
The simple truth is that NSLog is just plain slow.
But why? To answer that question, let's find out what NSLog does, and then how it does it.
What does NSLog do exactly?
NSLog does 2 things:
1. It writes log messages to the Apple System Logging (asl) facility. This allows log messages to show up in Console.app.
2. It also checks to see if the application's stderr stream is going to a terminal (such as when the application is being run via Xcode). If so it writes the log message to stderr (so that it shows up in the Xcode console).
Writing to STDERR doesn't sound difficult. That can be accomplished with fprintf and the stderr file descriptor reference. But what about asl?
The best documentation I've found about ASL is a 10 part blog post from Peter Hosey: link
Without going into too much detail, the highlight (as it concerns performance) is this:
To send a log message to the ASL facility, you basically open a client connection to the ASL daemon and send the message. BUT - each thread must use a separate client connection. So, to be thread safe, every time NSLog is called it opens a new asl client connection, sends the message, and then closes the connection. (1)
The lumberjack framework avoids much of the cost by creating a single re-usable asl client connection for its background logging thread.
^1 - Assuming that NSLog acts like its open-source cousin CFShow.
#####****我嘗試翻譯一下
所以關于NSLog 為什么慢
大體原因如下:
- NSLog,要寫信息到 ASL(Apple System Logging),這樣子log信息才會顯示到Console.app.
- 它還檢查應用程序的stderr流是否進入終端
- 要向ASL工具發送日志消息,您基本上打開與ASL守護程序的客戶端連接并發送消息。但是 - 每個線程必須使用單獨的客戶端連接。所以,要線程安全,每次NSLog被調用時,它將打開一個新的asl客戶端連接,發送消息,然后關閉連接。
或者使用iConsole.來統一處理log問題。
https://github.com/nicklockwood/iConsole
iConsole 可以通過pod 或者 拉源碼的方式到項目中,實現的大概原理是:使用一個 UITextView 來記錄項目中的log.每次可以這樣子使用
[iConsole log:@"some message"];
內部會把 some message 顯示在 UITextView 上,并且加上回車符??雌饋硐駛€控制臺。而且可以通過手勢調出。方便。
可以通過LLDB
.如果NSLog 只是為了在調試階段觀察值,那大可不要NSLog
要觀察某個值,下斷點,并且通過LLDB 輸入某個值
p po 命令。
當然,lldb 也可以臨時改變值。比如:
(lldb) e a = 200;
(int) $0 = 200
(lldb)
當然也可以修改背景色什么的。lldb 是個萬能包,
(lldb) e self.backgroundColor = [UIColor redColor];
(UICachedDeviceRGBColor *) $1 = 0x000000017446bb00
(lldb)
看,修改成功了!!!
如果沒有特殊需求,建議使用lldb解決log 以及測試代碼。畢竟log也是測試的一部分,不用全局入侵代碼。