在蘋果的官方文檔中列出了我們在調(diào)試中能用到的一些命令,我們在這重點(diǎn)講一些常用的命令
一、基本操作
1.1. 視圖層次
打印視圖層次 po [self.contentView recursiveDescription]
1.2. 改變某個(gè)取值
int a = 1;
//Console expr a=2
NSLog(@"實(shí)際值: %d", a);
1.3. call改變view的背景色
call [self.view setBackgroundColor:[UIColor redColor]]
1.4. 聲明變量
expr int $b=2 或者 e int $b=2
//輸出 po $b
1.5. 打印堆棧
ios中打印堆棧方法是 NSThread callStackSymbols,這里調(diào)試的時(shí)候有個(gè)簡單的方法如下
bt 或者 bt all
1.6. 更改方法返回值
thread return NO/YES
-(BOOL) returnYES
{
//thread return NO ,可以更改函數(shù)返回值
return YES;
}//方法返回結(jié)果為NO
1.7. 多線程異常后查看歷史對象的malloc分配歷史
先打開Enable Zombie Objects 和 Malloc Stack
(lldb) command script import lldb.macosx.heap
(lldb) malloc_info -S 0x7ff7206c3a70
1.8. 寄存器查找對象
曾經(jīng)遇到過一個(gè)問題,[self.tableview reloadData]直接奔潰。這時(shí)候tableview其實(shí)沒有問題,我們要怎么去找問題呢?

如上圖所示,最后我們通過malloc_info -S 0x00007fe99a629560來查看對象分配在堆里面的具體的地址,隨后在左側(cè)打開table的所有變量,輸入這個(gè)地址即能夠看到這個(gè)是什么成員。
常見問題-打印無效
上面我們簡單的學(xué)習(xí)了如何使用LLDB命令。但有時(shí)我們在使用這些LLDB命令的時(shí)候,依然可能會(huì)遇到一些問題。不明類型或者類型不匹配
p (void)NSLog(@"%@",[self.view viewWithTag:1001]) //記住要加void
p (CGRect)[self.view frame] //記住不能寫成 self.view.frame,lldb的bug
二、調(diào)試進(jìn)階
2.1. 監(jiān)聽某個(gè)方法的調(diào)用

如果是自定義的view,比如
QQView,想監(jiān)聽frame變化,直接[QQView setFrame:]即可系統(tǒng)方法就要如圖所示,x86_64系統(tǒng)中,rdi表示第一個(gè)參數(shù),具體其他平臺(tái)可看inspecting-obj-c-parameters-in-gdb,里面有詳細(xì)的說明
$rdi ? arg0 (self)
$rsi ? arg1 (_cmd)
$rdx ? arg2
$rcx ? arg3
$r8 ? arg4
$r9 ? arg5
2.2. image尋址,找到崩潰行
此時(shí)會(huì)調(diào)用如下代碼會(huì)崩潰
NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSLog(@"%@",arr[2]);
2015-06-30 14:47:59.280 QQLLDB[6656:138560] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
0 CoreFoundation 0x000000010b2d8c65 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010af71bb7 objc_exception_throw + 45
2 CoreFoundation 0x000000010b1cf17e -[__NSArrayI objectAtIndex:] + 190
3 QQLLDB 0x000000010aa404f6 -[ViewController viewDidLoad] + 1030
4 UIKit 0x000000010ba75210 -[UIViewController loadViewIfRequired] + 738
5 UIKit 0x000000010ba7540e -[UIViewController view] + 27
6 UIKit 0x000000010b9902c9 -[UIWindow
此時(shí)我們要直接找到崩潰的行數(shù),很簡單。先找到非系統(tǒng)bug的崩潰地址,如下圖所示,顯然是第三行QQLLDB,右邊對應(yīng)的地址是0x000000010aa404f6,然后輸入image lookup --address 0x000000010aa404f6,即可看到是60行出了bug
image lookup --address 0x000000010aa404f6
Address: QQLLDB[0x00000001000014f6] (QQLLDB.__TEXT.__text + 1030)
Summary: QQLLDB`-[ViewController viewDidLoad] + 1030 at ViewController.m:60
2.3. crash日志分析,讀取符號(hào)表
1.要知道如何讀取符號(hào)表,我們得先偽造一份符號(hào)表的數(shù)據(jù)文件出來,代碼如下
NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSLog(@"%@",arr[2]);
偽造步驟:
1.編譯到真機(jī)
2.然后進(jìn)入xcode將這個(gè)打開,找到QQLLDB.app.dSYM這個(gè)文件,偷偷拷貝一份到桌面
3.然后在product中clean一下工程
4.在真機(jī)上打開一個(gè)編譯進(jìn)去的程序,會(huì)出現(xiàn)圖
步驟如下圖所示:

)




之后在命令行操作
atos -o /Users/tomxiang/Desktop/符號(hào)表/QQLLDB.app.dSYM/Contents/Resources/DWARF/QQLLDB -l0x1000e8000 0x1000eebd4
//此時(shí)得到結(jié)果,告訴我們是ViewController的viewDidLoad的第62行崩潰
-[ViewController viewDidLoad] (in QQLLDB) (ViewController.m:62)
2.4 觀察實(shí)例變量的變化
假設(shè)你有一個(gè) UIView,不知道為什么它的 _layer 實(shí)例變量被重寫了 (糟糕)。因?yàn)橛锌赡懿⒉簧婕暗椒椒?,我們不能使用符?hào)斷點(diǎn)。相反的,我們想監(jiān)視什么時(shí)候這個(gè)地址被寫入。
首先,我們需要找到 _layer 這個(gè)變量在對象上的相對位置:
(lldb) p (ptrdiff_t)ivar_getOffset((struct Ivar*)class_getInstanceVariable([MyView class], "_layer"))
(ptrdiff_t) $0 = 8
現(xiàn)在我們知道 ($myView + 8) 是被寫入的內(nèi)存地址:
(lldb) watchpoint set expression -- (int *)$myView + 8
Watchpoint created: Watchpoint 3: addr = 0x7fa554231340 size = 8 state = enabled type = w
new value: 0x0000000000000000
這被以 wivar $myView _layer 加入到 Chisel 中。
2.5 打印所有方法進(jìn)行l(wèi)og分析

三、Chisel-facebook開源插件
1. 安裝方法:
git clone https://github.com/facebook/chisel.git ~/.chisel
echo "command script import ~/.chisel/fblldb.py">>~/.lldbinit
安裝好后,打開xcode就可以運(yùn)行調(diào)試了
2. 基本命令
2.1. 預(yù)覽圖片
UIImage *image = [UIImage imageNamed:@"clear"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
[viewB addSubview:imageView];
//此時(shí)執(zhí)行命令之后,圖片會(huì)被蘋果用自帶的預(yù)覽工具顯示出來
visualize image
2.2. 邊框/內(nèi)容著色
如下所示,打印得到imageView地址之后,然后用border命令將其邊框著色unborder取消著色
(lldb) p imageView
(UIImageView *) $2 = 0x00007fb8c9b15910
(lldb) border 0x00007fb8c9b15910 -c green -w 2
同理,mask是給內(nèi)容著色 unmask
mask imageView -c green
2.3. 關(guān)系鏈的繼承
(lldb) pclass image
UIImage
| NSObject
2.4. 打印所有屬性
pinternals這個(gè)命令就是打印出來的一個(gè)控件(id)類型的內(nèi)部結(jié)構(gòu),詳細(xì)到令人發(fā)指!甚至是你自定義的控件中的類型,譬如這個(gè)styleView就是我自定義的,內(nèi)部有個(gè)iconView的屬性,其中的值它也會(huì)打印出來。
(lldb) pinternals image
(UIImage) $8 = {
NSObject = {
isa = UIImage
}
_imageRef = 0x00007fc1f3330780
_scale = 2
_imageFlags = {
named = 1
imageOrientation = 0
cached = 0
hasPattern = 0
isCIImage = 0
renderingMode = 0
suppressesAccessibilityHairlineThickening = 0
hasDecompressionInfo = 0
}
}
2.5. bmessage
如果ChiselViewController沒有設(shè)置viewWillDisappear這個(gè)方法,此時(shí)我想用斷點(diǎn)斷下來,可以這樣
(lldb) bmessage -[ChiselViewController viewWillDisappear:]
Setting a breakpoint at -[UIViewController viewWillDisappear:] with condition (void*)object_getClass((id)$rdi) == 0x0000000100c47060
Breakpoint 2: where = UIKit`-[UIViewController viewWillDisappear:], address = 0x0000000101a0b566
三. Crash Callstack分析 - 進(jìn)?一步分析
| 屬性 | 說明 |
|---|---|
| 0x8badf00d | 在啟動(dòng)、終?止應(yīng)?用或響應(yīng)系統(tǒng)事件花費(fèi)過?長時(shí)間,意為“ate bad food”。 |
| 0xdeadfa11 | ?用戶強(qiáng)制退出,意為“dead fall”。(系統(tǒng)?無響應(yīng)時(shí),?用戶按電源開關(guān)和HOME) |
| 0xbaaaaaad | ?用戶按住Home鍵和?音量鍵,獲取當(dāng)前內(nèi)存狀態(tài),不代表崩潰 |
| 0xbad22222 | VoIP應(yīng)?用因?yàn)榛謴?fù)得太頻繁導(dǎo)致crash |
| 0xc00010ff | 因?yàn)樘珷C了被干掉,意為“cool off” |
| 0xdead10cc | 因?yàn)樵诤笈_(tái)時(shí)仍然占據(jù)系統(tǒng)資源(?比如通訊錄)被干掉,意為“dead lock” |
參考鏈接:
1.當(dāng)異常出現(xiàn)時(shí)
2.日志記錄CocoaLumberjack
3.在Xcode中調(diào)試程序
4.南峰子的技術(shù)博客
5.與調(diào)試器共舞 - LLDB 的華爾茲
6.官方調(diào)試技巧文檔
7.inspecting-obj-c-parameters-in-gdb