iOS調(diào)試技巧總結(jié)

對于大型APP,每次修改重新編譯,都需要幾分鐘時(shí)間,因此要在一次運(yùn)行中盡量多的解決問題,減少編譯的次數(shù)。
無論是需求的迭代,還是bug的調(diào)試,都可能會遇到陌生的代碼,對于不熟悉的代碼,如何調(diào)試呢?

一 打Log

只需要一行輸出函數(shù),即可看到各個(gè)方法的執(zhí)行順序,知道輸入、輸出值,但是對代碼入侵性太強(qiáng),并且頻繁修改消耗過多編譯的時(shí)間。

二 問寫代碼的人

最直接最高效。但是如果不經(jīng)過思考,就直接問,下次遇到類似的問題還是不會。因此我認(rèn)為最好先自己調(diào)試,如果幾個(gè)小時(shí)還無法解決,再請教。
對于遇到的問題,不能僅僅當(dāng)成一種需要完成的任務(wù),而應(yīng)該把它當(dāng)成一種成長的機(jī)會,擁有一顆成長型的心態(tài)。解決問題的同時(shí),自己也獲得了成長,這樣就不僅僅是自己在跑步,而是借助公司這輛汽車,達(dá)到遠(yuǎn)超跑步的速度。

三 控制臺調(diào)試

控制臺調(diào)試最核心的就是LLDB命令,LLDB是Xcode的默認(rèn)調(diào)試器,它高度利用LLVM項(xiàng)目中的現(xiàn)有庫,例如Clang表達(dá)式解析器和LLVM反匯編程序。

3.1 執(zhí)行命令:

expression命令,簡寫e,最基本的命令。

運(yùn)用實(shí)例:修改View的顏色

有時(shí)候我們需要找某個(gè)控件,或改某個(gè)控件的顏色,但是可能因?yàn)閷蛹壿^多而不是非常明顯的情況下,可以先在LLDB嘗試修改,看一下預(yù)覽的效果。

image.png

操作步驟如下:
1.先執(zhí)行
(lldb) p self.view
查看self.view存儲在變量 0變量 2.將0強(qiáng)轉(zhuǎn)為UIView類型,
(lldb) e (UIView *)0 轉(zhuǎn)存到了1
3.使用 1的layer改變顏色 (lldb) e1.layer.backgroundColor=[UIColor redColor].CGColor
4.執(zhí)行刷新,可以看到對應(yīng)的UIView立刻生效了。因?yàn)閿帱c(diǎn)會終止UI線程,所以這個(gè)命令是為了渲染修改后的界面。
(lldb) e [CATransaction flush]

實(shí)際運(yùn)用 暗黑適配

我們團(tuán)隊(duì)今年進(jìn)行了暗黑模式適配,在改別人的代碼時(shí),尤其是層級非常多的時(shí)候,用此來調(diào)整、預(yù)覽,可以快速定位需要修改的控件。

3.2 打印命令

1)print:簡寫pri或p,其實(shí)print是"expression --"的簡寫('print' is an abbreviation for 'expression --')。
2)po:用來打印對象
3)call:調(diào)用方法。在調(diào)試時(shí),想要額外調(diào)用一下某個(gè)方法,可以使用call命令,如圖
call [self callMethod]

image.png

3.3 線程

1)thread jump --by N
功能:在某處斷點(diǎn),跳過之后的N行代碼。其效果等同于注釋了N行代碼。
使用場景:有時(shí)候需要注釋幾行代碼,使用此命令,不用重新編譯即可立刻看到效果。
2)thread backtrace 查看線程堆棧信息,簡寫為bt。
3)thread return X
令某個(gè)方法直接返回X。

運(yùn)用實(shí)例:

(lldb) thread return XXX

image.png

如圖,在25行執(zhí)行了
(lldb) thread return @"changeReturn"
可以看到- (NSString *)threadReturn 返回的值就變成了@"changeReturn"。

3.4 觀察點(diǎn) watchpoint

作用:可以觀察某個(gè)變量,在變化時(shí)其會自動暫停斷點(diǎn)至其相應(yīng)位置。
使用方式:(lldb) watchpoint set variable name
或者右鍵其,點(diǎn)擊watch variable
注意:如果需要觀測self.name,則要寫成self->_name。對于觀測普通類型的變量,比如button的 state值,_state不存在。在LLDB調(diào)試框可以右鍵這個(gè)值。

使用場景:當(dāng)某個(gè)變量值突然被改變,但是又找不到是在哪里改變。使用此即可跟蹤其變化。
如果不使用變量觀測,就需要重寫某個(gè)類的某個(gè)setter方法。

四、斷點(diǎn)調(diào)試

先來介紹一下基本的界面:

image.png

這5個(gè)按鈕,分別是:
1 啟動/禁用斷點(diǎn)
2 繼續(xù)執(zhí)行程序
3 執(zhí)行下一步
4 進(jìn)入方法
5 跳出方法
這幾個(gè)可視化的按鈕,在LLDB中都有相應(yīng)的命令,
1 breakpoint enable/disabled
2 continue
3 next
4 step
5 finish
但是因?yàn)榘粹o更方便,所以通常也不用命令。

4.1 異常斷點(diǎn)

異常斷點(diǎn)是為了拋出異常時(shí),crash顯示到具體的行,而不是main.m中。加上如圖的斷點(diǎn)即可。

image.png

4.2 符號斷點(diǎn)

符號斷點(diǎn)是針對某個(gè)方法執(zhí)行的斷點(diǎn),
實(shí)際開發(fā)中,當(dāng)我們操作了某個(gè)路徑會執(zhí)行A方法,但是A方法用于很多個(gè)地方,并不知道具體是在哪里執(zhí)行的,如果是傳統(tǒng)的方法,就全局搜索A方法,全部打上斷點(diǎn)。實(shí)際上可以用符號斷點(diǎn)來解決這個(gè)問題。
只要對某個(gè)方法打上符號斷點(diǎn),那么所有調(diào)用它的地方,都會暫停。

注意:+,-方法寫清楚。:之后不能有空格

另外。對于寫得比較標(biāo)準(zhǔn)的代碼,幾個(gè)類似的方法,最終應(yīng)該調(diào)用一個(gè)統(tǒng)一的方法,叫做全能初始化方法,用NS_DESIGNATED_INITIALIZER標(biāo)識。只需要對全能初始化方法打符號斷點(diǎn)即可。

4.3 編輯斷點(diǎn)

image.png

右鍵點(diǎn)擊某一行,即可打開:


image.png

1)Condition

條件斷點(diǎn),對于循環(huán)次數(shù)非常多的for循環(huán),有時(shí)我們需要其在指定的i值時(shí)才暫停,或者某兩個(gè)變量相等時(shí)才暫停。

2)Ignore

忽視次數(shù)N,即N次之后才會暫停。

3)Action

有些問題通過斷點(diǎn)無法解決,因?yàn)閿帱c(diǎn)操作需要幾秒的操作時(shí)間。而輪詢類的邏輯,幾秒之后其值就變化了。這類問題通常是需要打Log的,但是打Log重新編譯消耗過多的時(shí)間,如何在不改變代碼、重新編譯的前提下打Log呢?這時(shí)Action就起了很大的作用。

(1)Debugger Command
這個(gè)功能相當(dāng)強(qiáng)大,可以在某一行直接插入新的代碼并且不用重新編譯。
(2)Log Message
打Log,格式:@exp@,exp指的是變量名。%B:指的是此行所在的方法名。%H:計(jì)數(shù)器。
缺點(diǎn):Log Message 適合低頻的打印。如果是秒級更新的Log。不適用,每秒打印一次會非??ā?br> (3)Sound:當(dāng)斷點(diǎn)到這里時(shí),發(fā)出聲音,作用和Log一樣,只不過從文字變成了聲音。
(4)AppleScript,可以執(zhí)行蘋果原生的腳本。
(5)Shell Command,可以執(zhí)行shell腳本。

五 視圖查看

有時(shí)候需要對可視的某個(gè)控件進(jìn)行需求,這種情況可以通過視圖結(jié)構(gòu),直接找到對應(yīng)的類名。雖然不能直接解決問題,但是對于找到問題根源所在,有一定幫助。

5.1原生的Debug View Hierarchy

Debug View Hierarchy,無論是性能性,還是操作方便度上,都比較差。

5.2 Reveal

reveal這是一個(gè)專業(yè)的團(tuán)隊(duì)做的軟件,非常好用,只不過需要一些配置。
詳見http://www.itdecent.cn/p/ced27bec87b4

image.png

5.3 Chisel

Chisel的visualize,facebook出的一個(gè)開源LLDB框架,可以在斷點(diǎn)的時(shí)候查看某個(gè)類的視圖。

六 LLDB擴(kuò)展

facebook開源了chisel,可以添加腳本到LLDB。
源碼:https://github.com/facebook/chisel
chisel提供了幾個(gè)命令,對LLDB的功能進(jìn)一步加強(qiáng)。

1)visualize:預(yù)覽整個(gè)view的圖。
相比原生的命令,看到的不僅僅是一個(gè)控件的圖像,而可以是多個(gè)view的組合。

七 網(wǎng)絡(luò)請求的抓包

對于網(wǎng)絡(luò)請求,可以在請求的回調(diào)中打斷點(diǎn)、Log,查看返回的結(jié)果。但是對于輪詢的請求,打斷點(diǎn)太慢,打Log在調(diào)試框中展示的內(nèi)容又太多,會刷屏。因此可以用抓包工具,對所有的請求都進(jìn)行了整理。
1 charles:古老的抓包工具,不想買軟件的話可以免費(fèi)使用。
2 proxyman,新起之秀,個(gè)人認(rèn)為無論是基礎(chǔ)功能,還是界面,都已經(jīng)超越了Charles。

image.png

3 wireshark,適用于基于TCP/UDP或藍(lán)牙協(xié)議的硬件的抓包。

八 靜態(tài)分析

靜態(tài)分析,可以在編碼的階段就能檢測出一些潛在的問題。
原生的Analyze,以及三方的Clang,Infer,OCLint。

九 參考文獻(xiàn)

http://lldb.llvm.org/
http://www.itdecent.cn/p/d0b9fd8ffadc
https://developer.apple.com/videos/play/wwdc2018/412/?time=182

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

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 今天花了一天的時(shí)間終于把iOS的幾種常見的調(diào)試方法給學(xué)習(xí)了一下,在這里給大家分享一下LLDB的使用,同時(shí)也是...
    Peak_One閱讀 11,304評論 5 33
  • 前言 LLDB是個(gè)開源的內(nèi)置于XCode的具有REPL(read-eval-print-loop)特征的Debug...
    Noskthing閱讀 18,720評論 10 89
  • 劍未配好,出門已是江湖。 最近一直沒有更新簡書是因?yàn)樵陂_發(fā)和測試階段,有任務(wù),沒有進(jìn)行學(xué)習(xí),不過在做任務(wù)的時(shí)...
    和玨貓閱讀 8,500評論 9 75
  • NSLog,po命令和普通斷點(diǎn)調(diào)試相信每個(gè)iOS開發(fā)者都會,這里就不作介紹了。 一、Memory Graph Xc...
    wu大維閱讀 12,416評論 16 186
  • 久違的晴天,家長會。 家長大會開好到教室時(shí),離放學(xué)已經(jīng)沒多少時(shí)間了。班主任說已經(jīng)安排了三個(gè)家長分享經(jīng)驗(yàn)。 放學(xué)鈴聲...
    飄雪兒5閱讀 7,833評論 16 22

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