XCode的一些調試技巧蒐集

XCode 內置GDB,咱們能夠在命令行中使用 GDB 命令來調試咱們的程序。下面將介紹一些經常使用的命令以及調試技巧。app

po 命令:爲 print object 的縮寫,顯示對象的文本描述(顯示從對象的 description 消息得到的字符串信息)。iphone

好比:函數

上圖中,我使用 po 命令顯示一個 NSDictionary 的內容。注意在左側咱們能夠看到 dict 的一些信息:3 key/value pairs,顯示該 dict 包含的數據量,而展開的信息顯示 isa 層次體系(即class 和 metaclass結構關係)。咱們能夠右擊左側的 dict,選中「Print Description of "dict"」,則能夠在控制檯輸出 dict 的詳細信息:工具

[cpp] view plaincopyprint?ui

Printing description of dict:  spa

<CFBasicHash 0x1001149e0 [0x7fff7e27ff40]>{type = immutable dict, count = 3,  命令行

entries =>  debug

    0 : <CFString 0x100002458 [0x7fff7e27ff40]>{contents = "first"} = <CFString 0x100002438 [0x7fff7e27ff40]>{contents = "one"}  3d

    1 : <CFString 0x100002498 [0x7fff7e27ff40]>{contents = "second"} = <CFString 0x100002478 [0x7fff7e27ff40]>{contents = "two"}  調試

    2 : <CFString 0x1000024d8 [0x7fff7e27ff40]>{contents = "third"} = <CFString 0x1000024b8 [0x7fff7e27ff40]>{contents = "three"}  

}  

(gdb)   


print 命令:有點相似於格式化輸出,能夠輸出對象的不一樣信息:

如:

[cpp] view plaincopyprint?

(gdb) print (char *)[[dict description] cStringUsingEncoding:4]  

$1 = 0x1001159c0 "{\n    first = one;\n    second = two;\n    third = three;\n}"  

(gdb) print (int)[dict retainCount]  

$2 = 1  

(gdb)   

注:4是 NSUTF8StringEncoding 的值。

 

info 命令:咱們能夠查看內存地址所在信息

好比 "info symbol 內存地址" 能夠獲取內存地址所在的 symbol 相關信息:

[cpp] view plaincopyprint?

(gdb) info symbol 0x00000001000017f7  

main + 343 in section LC_SEGMENT.__TEXT.__text of /Users/LuoZhaohui/Library/Developer/Xcode/DerivedData/RunTimeSystem-anzdlhiwvlbizpfureuvenvmatnp/Build/Products/Debug/RunTimeSystem  

好比 "info line *內存地址" 能夠獲取內存地址所在的代碼行相關信息:

[cpp] view plaincopyprint?

(gdb) info line *0x00000001000017f7  

Line 62 of "/Users/LuoZhaohui/Documents/Study/RunTimeSystem/RunTimeSystem/main.m" starts at address 0x1000017f7 <main+343> and ends at 0x10000180a <main+362>.  


show 命令:顯示 GDB 相關的信息。如:show version 顯示GDB版本信息

[cpp] view plaincopyprint?

(gdb) show version  

GNU gdb 6.3.50-20050815 (Apple version gdb-1708) (Mon Aug  8 20:32:45 UTC 2011)  

Copyright 2004 Free Software Foundation, Inc.  

GDB is free software, covered by the GNU General Public License, and you are  

welcome to change it and/or distribute copies of it under certain conditions.  

Type "show copying" to see the conditions.  

There is absolutely no warranty for GDB.  Type "show warranty" for details.  

This GDB was configured as "x86_64-apple-darwin".  

 

help 命令:若是忘記某條命令的語法了,可使用 help 命令名 來獲取幫助信息。如:help info 顯示 info 命令的用法。

[cpp] view plaincopyprint?

(gdb) help info  

Generic command for showing things about the program being debugged.  

List of info subcommands:  

info address -- Describe where symbol SYM is stored  

info all-registers -- List of all registers and their contents  

info args -- Argument variables of current stack frame  

info auxv -- Display the inferior's auxiliary vector  

info breakpoints -- Status of user-settable breakpoints  

info catch -- Exceptions that can be caught in the current stack frame  

info checkpoints -- Help  

info classes -- All Objective-C classes  

......  

Type "help info" followed by info subcommand name for full documentation.  

Command name abbreviations are allowed if unambiguous.  

(gdb)   


在系統拋出異常處設置斷點

有時候咱們的程序不知道跑到哪一個地方就 crash 了,而 crash 又很難重現。保守的作法是在系統拋出異常以前設置斷點,具體來講是在 objc_exception_throw處設置斷點。設置步驟爲:首先在 XCode 按 CMD + 6,進入斷點管理窗口;而後點擊右下方的 +,增長新的 Symbolic Breakpoint,在 Symbol 一欄輸入:objc_exception_throw,而後點擊 done,完成。 這樣在 Debug 模式下,若是程序即將拋出異常,就能在拋出異常處中斷了。好比在前面的代碼中,我讓 [firstObjctcrashTest]; 拋出異常。在 objc_exception_throw 處設置斷點以後,程序就能在該代碼處中斷了,咱們從而知道代碼在什麼地方出問題了。


 

  1. 命 令                        解釋  
  2. break NUM               在指定的行上設置斷點。  
  3. bt                      顯 示全部的調用棧幀。該命令可用來顯示函數的調用順序。  
  4. clear                   刪 除設置在特定源文件、特定行上的斷點。其用法爲:clear FILENAME:NUM。  
  5. continue                繼續執行正在調試的程序。該命令用在程序 因爲處理信號或斷點而  
  6.                         致使中止運行 時。  
  7. display EXPR            每次程序中止後顯示錶達式的值。表達式由程序定 義的變量組成。  
  8. file FILE               裝載指定的可執行文件進行調試。  
  9. help NAME               顯 示指定命令的幫助信息。  
  10. info break              顯 示當前斷點清單,包括到達斷點處的次數等。  
  11. info files              顯 示被調試文件的詳細信息。  
  12. info func               顯示全部的函數名稱。  
  13. info local              顯 示當函數中的局部變量信息。  
  14. info prog               顯示被調試程序的執行狀 態。  
  15. info var                顯示全部的全局和靜態變量名稱。  
  16. kill                    終 止正被調試的程序。  
  17. list                    顯示源代碼段。  
  18. make                    在 不退出 gdb 的狀況下運行 make 工具。  
  19. next                    在 不單步執行進入其餘函數的狀況下,向前執行一行源代碼。  
  20. print EXPR              顯 示表達式 EXPR 的值。  
  21.   
  22. print- object            打印一個對象  
  23. print (int) name      打印一個類型  
  24. print- object [artist description]   調用一個函數  
  25. set artist = @"test"    設置變量值  
  26. whatis                      查 看變理的數據類型  

 

 

 
Crash的問題。Crash最多的無非就兩種,一種就是signal SIGABRT,大概的意思就是發送Message出現問題,信號迷失了。這種的Crash實際上是很好定位,Crash了後直接看Console裏出的最後日誌,好比這段:
 
2012-03-28 19:26:33.055 TableViewMenuDemo[3916:f803] *** Terminating app due to uncaught exception ‘NSInvalidArgumentException’, reason: ‘-[__NSArrayI replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance 0x6a3f3d0′
 
*** First throw call stack:
 
找到reason字段,那就是緣由,說NSArray 調用replaceObjectAtIndex:withObject:
 
這個方法是NSMutableArry的,NSArray並無該方法。信號迷失掉了,因此Crash了。0x6a3f3d0 是出問題的內存地址,查下內存地址或搜下調用方法就比較好定位了。
 
 
Xcode4上還有個更好用的定位方法,就是設置一個Exception Breakpoint就行了。
 
看圖在工程的左邊欄中選擇Breakpoint Navigator,點擊下面的+號添加一個Exception Breakpoint,而後再運行試試,Crash後,是否是直接定位到了那行代碼了?再根據Console裏的日誌進行定位修改就行了。
 
下面說說另外一種Crash, EXC_BAD_ACCESS,這個比較頭疼,由於Crash的時候,多是比較早以前的某個變量釋放了,如今訪問時出問題。Console裏也沒顯示什麼日誌。
 
這裏光加入Exception Breakpoint是不夠的了,XCode4還個可愛的地方,打開Scheme選項選擇EditScheme。
 
 
 
而後按圖勾上Enable Zombie Objects和Malloc Stack那兩項,記住通常只有在定位EXC_BAD_ACCESS時候才勾選,別有事沒事都勾上。
 
這樣從新跑一下,若是是到Exception Breakpoint處中止了,能夠在Console中輸入:c(continue)按回車繼續跑,直到Crash。看下Console是否是有跟SIGABRT相似的錯誤信息日誌了,後面定位什麼的你懂的。
 
若是尚未日誌,在Console中輸入po$eax$eax標誌出錯的地方,適用模擬器,真機用$r0(話說EXC_BAD_ACCESS這種錯誤模擬器定位就行),還能夠輸入好比:po[$eaxname]po[$eaxreason]等指令查看錯誤其餘信息(注意方括號後沒分號的)。而後,就沒有而後了。
 
還要補充點,程序開發過程就要多關注左邊欄中Issue Navigator裏的警告信息,Xcode4不只會警告,還多數給出解決建議,能避免後面沒必要要的Crash。
 
 
若是程序Crash,第一時間關注下debug Navigator裏的執行信息,將滑塊拉向右邊能夠看到更多調用信息,根據這個能大體設想是調用什麼方法或進行什麼操做時Crash的。
 
 
 

一、使用殭屍變量(NSZombieEnabled)

 二、重寫object的respondsToSelector方法

在iphone開發的時候EXC_BAD_ACCESS這個bug時不容易找到緣由的。

首先說一下EXC_BAD_ACCESS 這個錯誤,能夠這麼說,90%的錯誤來源在於對一個已經釋放的對象進行release操做,或者操做一個在循環代碼中被修改的序列中的對象。雖然使用NSZombieEnabled變量能夠幫助你找到問題所在,但有的時候,即便經過設置NSZombieEnabled變量,仍是不能定位到問題所在,這個時候,你能夠試試重寫object的respondsToSelector方法,顯示出現EXEC_BAD_ACCESS前訪問的最後一個object,下面是具體的步驟:
a、在每一個類而且在 other c flags中加入-D _FOR_DEBUG_(記住請只在Debug Configuration下加入此標記)。這樣當你程序崩潰時,Xcode的console上就會準確地記錄了最後運行的object的方法。的實現文件(.m,.mm)文件中,添加以下代碼:
[cpp] 
-(BOOL) respondsToSelector : (SEL)aSelector { 
    printf("SELECTOR: %s\n", [NSStringFromSelector(aSelector) UTF8String]); 
    return [super respondsToSelector:aSelector]; 

b、而且在 other c flags中加入-D _FOR_DEBUG_(記住請只在Debug Configuration下加入此標記)。這樣當你程序崩潰時,Xcode的console上就會準確地記錄了最後運行的object的方法。

三、讓XCode反饋足夠多的信息

在Edit–>Scheme裏面 找到Arguments ,在Environment Variables這裏添加
把下面2個值設置成YES
NSAutoreleaseFreedObjectCheckEnabled
NSDebugEnabled
這種方法很是好用,建議在創建一個工程的時候,加入此設置

四、設置全局異常斷點

在程序拋出異常時候,每每須要定位到異常
鍵入快捷鍵 cmd + 6 進入斷點窗口,點擊左下角的"+"按鈕,選擇彈出框的「Add Exception BreakPoint」項,以下圖所示:加載中...

而後使用默認設置,點擊"done"按鈕,設置全局異常斷點就完成了

相關文章
相關標籤/搜索