參考:http://blog.csdn.net/xunyn/article/details/39473251
開胃小菜--簡單的斷點調試
在xcode中打開一個app,在想要break的行號上單擊,即可生成一個深色的箭頭標識--斷點。如下圖,在viewDidLoad:中設置了斷點。
運行app,等待。。。就可以看到xcode在斷點處進入調試模式,現在讓我們把視線移到xcode右下角的控制檯,有木有看到(lldb)這樣一行,鼠標移到此行,輸入
1
|
po
[self view] |
po(print object)是LLDB的一個命令,其主要功能是輸出objective-c中對象(objects)的信息,與之相似的另外一個命令是 p(print),其主要功能是輸出原生類型(boolean、integer、float、etc)的信息。
注意這個使用了類型轉換告知調試器應該如何處理返回值。
技巧一:運行時修改變量的值
你以前怎麼驗證是不是某個變量的值導致整段程序不能正常工作?修改代碼中的變量的值,然後cmd+r重新啓動app?現在你不需要這麼做了,只需要設置一個斷點,當程序在這進入調試模式後,使用expr命令即可在運行時修改變量的值。
假如有一個loginWithUsername:方法,需要兩個參數:username,password。
首先設置好斷點,如下圖所示:
運行app,進入斷點模式後,在(lldb)後輸入
1
2
|
expr
username = @ "username" expr
password = @ "badpassword" |
1
2
|
(NSString
*) $0 = 0x3d3504c4 @ "username" (NSString
*) $1 = 0x1d18ef60 @ "badpassword" |
1
2
|
(0x1c59aae0)
A line for the
breakpoint (0x1c59aae0)
Username and Password after: username:badpassword |
右擊斷點選擇“Edit Breakpoint...”(或者按住cmd+option,單擊斷點),然後如下圖所示設置斷點
注意選中了最後一行(“Automatically continue after evaluating”)的選擇框,這就保證運行到這個斷點的時,填充變量的值,然後繼續運行,並不在此處斷點進入調試模式。
運行app,你會得到和上述手動設置變量的值一樣的輸出。
接下來單擊斷點,使其處於禁用狀態,現在箭頭的顏色應該是淺藍色的,重新運行app,你會發現username和password的值沒有在運行時被改變了。
技巧二:設置斷點觸發條件
斷點的另外一個重要作用,是可以設置觸發斷點生效的條件,這樣我們就可以在運行時針對特定的數據進行分析,觀察app是否運行在正確的軌道上。如下圖:
上述截圖可以看到如下語句
1
|
( BOOL )[(NSString*)[item
valueForKey:@ "ID" ]
isEqualToString:@ "93306" ] |
技巧三:格式化輸出數據
如果你厭倦了代碼裏無窮無盡的NSLog,幸運的是我們可以在編輯斷點使其輸出格式化字符串就像平常編碼時一樣。不過有一點需要注意,平常編碼時可能會使用NSString‘s stringWithFormat:輸出格式化字符串,不過這個方法貌似在斷點中木有效果,你需要使用alloc/init形式的方法,如下:
1
|
po
[[NSString alloc] initWithFormat:@ "Item
index is: %d" ,
index] |
運行app,就能在控制檯看到想要的輸出啦!
雖然NSLog非常有用,但是在真機上,從NSLog打印出來的任何內容都會被保留,隱藏所有人都可以看到——只需要將設備連接到電腦,然後打開Xcode中的organiser,並定位到console,就可以看到每條log信息。可能你會意識到,這會帶來一些嚴重的影響!想一下,如果你將一些保密的算法邏輯,或者用戶密碼打印到控制檯!因此,如果蘋果檢測到在production build中,輸出許多內容到控制檯時,你的應用可能會被蘋果拒絕上架到商店。
幸運的是,這裏有一個最簡單的辦法進行log——通過一個宏,讓NSLog只在debug build的時候起作用。將這個功能添加到全局都能訪問得到的頭文件中。這樣你就可以盡情的使用log了,並且當進行production時,不會包含log相關代碼。如下代碼:
#ifdef DEBUG #define DMLog(...) NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__]) #else #define DMLog(...) do { } while (0)
現在如果使用DMLog,那麼將只會在debug build期間打印出log。而production build時則不會有任何log。通過 __PRETTY_FUNCTION\__ 可以打印出打印log所在的函數。
(順便說一下NSLog)
雖然NSLog非常出色,但它也有一些限制:
- 只能在本地打印
- 不支持帶級別的log(例如嚴重、警告等)
- NSLog效率低。在進行大量處理時,NSLog會嚴重影響程序的執行效率
互聯網上也有一些框架可以進行日誌記錄,通過這些框架可以避免NSLog的一些限制。下面有兩個不錯的:
- Cocoa LumberJack – 這是針對Cocoa非常出名的一個日誌框架。雖然剛開始用的時候會費勁點,但是它非常強大。
- SNLog – NSLog的一個替代品。
雖然ARC可以對內存進行有效的管理,不過在對象的生命週期內跟蹤一些重要的事件仍然是重要的。畢竟ARC並不能完全消除內存泄露的可能性,或者確保訪問的是一個被release掉的對象(ARC只是儘量避免這樣的情況發生)。爲此,我們可以使用一些方法和工具來觀察並留意對象在做些什麼。
在一個Objective-C對象的生命週期中有兩個重要的方法:init和dealloc。將這兩個方法調用的事件log到控制檯是不錯的選擇——你可以通過控制檯觀察到對象生命的開始,更重要的是,可以確保對象的釋放。
技巧四:the recursiveDescription
另外非常有用(但是被隱藏的命令)可以非常容易的對view進行檢查——the recursiveDescription 命令——在view上調用這個命令可以打印出view的繼承關係。