xcode調(diào)試效率

蘋果的官方文檔中列出了我們在調(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 ObjectsMalloc 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)用

image.png

如果是自定義的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)圖

步驟如下圖所示:

xcode工程

)
右鍵打開

包內(nèi)容

View Device Logs

找到文件

之后在命令行操作

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分析

打印log"

三、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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容