什么是GDB和LLDB
我們?cè)陂_發(fā)iOS程序的時(shí)候常常會(huì)用到調(diào)試跟蹤,如何正確的使用調(diào)試器來debug十分重要。xcode里有內(nèi)置的Debugger,老版使用的是GDB,xcode自4.3之后默認(rèn)使用的就是LLDB了。
GDB:
UNIX及UNIX-like下的調(diào)試工具。
LLDB:
LLDB是個(gè)開源的內(nèi)置于XCode的具有REPL(read-eval-print-loop)特征的Debugger,其可以安裝C++或者Python插件。
所以他們兩個(gè)都是調(diào)試用的Debugger,只是LLDB是比較高級(jí)的版本,或者在調(diào)試開發(fā)iOS應(yīng)用時(shí)比較好用,不然人家蘋果為什么換成了LLDB了呢!
lldb與gdb命令名的對(duì)照表:http://lldb.llvm.org/lldb-gdb.html
LLDB的使用
在程序里你需要的地方設(shè)置斷點(diǎn)。當(dāng)斷點(diǎn)斷住的時(shí)候你就能看到我們進(jìn)入LLDB調(diào)試器了。
這時(shí)我們就可以使用一些LLDB命令來進(jìn)行一些調(diào)試了。
調(diào)試快捷鍵:(Xcode常用快捷鍵)
command+shift+Y 打開調(diào)試窗口
command+Y 調(diào)試運(yùn)行程序
command+option+P 繼續(xù)
command+shift+O 跳過
command+shift+I 進(jìn)入
command+shift+T 跳出
help命令
help會(huì)列出所有命令列表,用戶加載的插件一般來說列在最后。
執(zhí)行help 可以打印指定command的幫助信息。
比如:help print會(huì)打印內(nèi)建命令print的使用幫助。
print命令
print命令的簡(jiǎn)化方式有prin pri p,唯獨(dú)pr不能用來作為檢查,因?yàn)闀?huì)和process混淆,幸運(yùn)的是p被lldb實(shí)現(xiàn)為特指print。
實(shí)際上你會(huì)發(fā)現(xiàn),lldb對(duì)于命令的簡(jiǎn)稱,是頭部匹配方式,只要不混淆,你可以隨意簡(jiǎn)稱某個(gè)命令。
例如:
最前面的(int)是類型。$是命令結(jié)果的引用名,使用$0可以進(jìn)行print $0 + 7這樣打印出17。
輸出view 下 subview 的數(shù)量。
由于 subview 的數(shù)量是一個(gè) int 類型的值,所以我們使用命令p:
(lldb)p (int)[[[self view] subviews] count]
直接調(diào)用方法改變背景顏色之類
其實(shí)使用p,po,call都可以調(diào)用方法,只是p和po都是用于輸出的有返回值的。call一般只在不需要顯示輸出,或是方法無返回值時(shí)使用。
(lldb)p [self.view setBackgroundColor:[UIColor redColor]]
(lldb)p (void)[CATransaction flush]
上述的p一般使用call比較好,因?yàn)榉椒ㄊ菦]有返回值的。
po命令
命令po跟p很像。p輸出的是基本類型,po輸出的Objective-C對(duì)象。調(diào)試器會(huì)輸出這個(gè) object 的 description。
例如:
expression命令
expression的簡(jiǎn)寫就是e??梢杂胑xpression來聲明新的變量,也可以改變已有變量的值。我們看到e聲明的都是$開頭的變量。我們?cè)谑褂脮r(shí)也需要加上$符號(hào)。
例如:
創(chuàng)建新的變量
注意:如果上面這里輸入以下命令,會(huì)發(fā)生錯(cuò)誤。說明lldb無法判定某一步的計(jì)算結(jié)果是什么數(shù)據(jù)類型,這時(shí)需要強(qiáng)制類型轉(zhuǎn)換來告訴lldb。
(lldb) p [[$array objectAtIndex:0] characterAtIndex:0]
error: no known method '-characterAtIndex:'; cast the message send to the method's return type
error: 1 errors parsing expression
(lldb) p (char)[[$array objectAtIndex:0] characterAtIndex:0]
'o'
修改已有變量
image命令
image 命令可用于尋址,有多個(gè)組合命令。比較實(shí)用的用法是用于尋找棧地址對(duì)應(yīng)的代碼位置。 下面我寫了一段代碼
NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSLog(@"%@",arr[2]);
這段代碼有明顯的錯(cuò)誤,程序運(yùn)行這段代碼后會(huì)拋出下面的異常:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
0 CoreFoundation 0x0000000101951495 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001016b099e objc_exception_throw + 43
2 CoreFoundation 0x0000000101909e3f -[__NSArrayI objectAtIndex:] + 175
3 ControlStyleDemo 0x0000000100004af8 -[RootViewController viewDidLoad] + 312
4 UIKit 0x000000010035359e -[UIViewController loadViewIfRequired] + 562
5 UIKit 0x0000000100353777 -[UIViewController view] + 29
6 UIKit 0x000000010029396b -[UIWindow addRootViewControllerViewIfPossible] + 58
7 UIKit 0x0000000100293c70 -[UIWindow _setHidden:forced:] + 282
8 UIKit 0x000000010029cffa -[UIWindow makeKeyAndVisible] + 51
9 ControlStyleDemo 0x00000001000045e0 -[AppDelegate application:didFinishLaunchingWithOptions:] + 672
10 UIKit 0x00000001002583d9 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 264
11 UIKit 0x0000000100258be1 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1605
12 UIKit 0x000000010025ca0c -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 660
13 UIKit 0x000000010026dd4c -[UIApplication handleEvent:withNewEvent:] + 3189
14 UIKit 0x000000010026e216 -[UIApplication sendEvent:] + 79
15 UIKit 0x000000010025e086 _UIApplicationHandleEvent + 578
16 GraphicsServices 0x0000000103aca71a _PurpleEventCallback + 762
17 GraphicsServices 0x0000000103aca1e1 PurpleEventCallback + 35
18 CoreFoundation 0x00000001018d3679 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
19 CoreFoundation 0x00000001018d344e __CFRunLoopDoSource1 + 478
20 CoreFoundation 0x00000001018fc903 __CFRunLoopRun + 1939
21 CoreFoundation 0x00000001018fbd83 CFRunLoopRunSpecific + 467
22 UIKit 0x000000010025c2e1 -[UIApplication _run] + 609
23 UIKit 0x000000010025de33 UIApplicationMain + 1010
24 ControlStyleDemo 0x0000000100006b73 main + 115
25 libdyld.dylib 0x0000000101fe95fd start + 1
26 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
現(xiàn)在,我們懷疑出錯(cuò)的地址是0x0000000100004af8(可以根據(jù)執(zhí)行文件名判斷,或者最小的棧地址)。為了進(jìn)一步精確定位,我們可以輸入以下的命令:
(lldb)image lookup --address 0x0000000100004af8
(lldb)im loo -a 0x0000000100004af8
命令執(zhí)行后返回:
Address: ControlStyleDemo[0x0000000100004af8] (ControlStyleDemo.__TEXT.__text + 13288)
Summary: ControlStyleDemo`-[RootViewController viewDidLoad] + 312 at RootViewController.m:53
我們可以看到,出錯(cuò)的位置是RootViewController.m的第53行。