iOS調試進階-更高效的使用Xcode和LLDB

你是否苦惱於每次改完 Bug 都要從新運行來驗證結果?你是否苦惱於修改 UI 問題不能所見即所得?你是否苦惱於修改一個小問題而要屢次等待從新編譯運行的時間?如今,經過對本篇文章的學習,不只能夠解決你的苦惱,還能夠提高你的 Debug 能力,使你再也不侷限於只利用斷點使用p/po來打印的變量的值。express

如下是本文的主要內容:bash

  • 修改簡單的邏輯 - expression
  • 跳過不想執行的語句 - thread jump
  • 經過 Debug 修改 UI - recursiveDescription

廢話很少說,讓咱們開始吧!app

expression 的使用

在咱們平常開發中,常常會碰到一些某些特定狀況下出現 Bug 的問題,好比下面這段代碼:框架

// Bug: 減操做錯誤,應該減一
if isAdd {
    count = count + 1
} else {
    count = count - 2
}
countLabel.text = "\(count)"
複製代碼

代碼說明:ide

isAdd 是一個布爾值,咱們經過這個布爾值來對count進行相應操做。
正常的需求是:若是isAdd是true咱們則對count進行加一操做;
若是isAdd是false咱們則對count進行減一的操做。
複製代碼

如今根據上下文isAdd的值爲true,假如咱們要測試爲false的狀況,咱們可能會在項目中手動將isAdd設爲false在從新運行項目驗證修改的結果。那麼咱們如何在不用從新運行項目的狀況下修改isAdd的值呢?答案就是 expression 了。post

expression 有兩種使用方式:學習

  • 在 LLDB 中輸入:每次都要輸入
  • 在斷點中配置:只需輸入一次

在 LLDB 中的使用

在斷點中的配置

下面是具體操做流程:測試

  • if isAdd {這行代碼打一個斷
  • 右鍵斷點選擇 edit Breakpoint
  • 點擊彈出框的 Action 按鈕,在下方的文本框輸入expression isAdd = false
  • 選中 optional 選項

再進行相關操做,就看見 if 語句執行的是 else 的分支了,同理你也能夠將count = count - 1設置爲表達式來驗證結果。ui

plus:編輯過的斷點會在箭頭內部添加一個白色三角形,具體可見上方的兩個圖的區別。這樣可使咱們更方便的找到已經編輯過的斷點。spa

thread jump 的使用

當咱們想跳過一行代碼的時候咱們可使用這個命令,當咱們使用的時候,Xcode 會彈出一個警告,告訴咱們這種作法很危險。因此,咱們使用的時候要確保不會出現問題再使用。

具體使用與上面的步驟相似,惟一的不一樣就是把上面的命令替換爲thread jump --by 1。該命令的1就是跳過1行的意思,咱們能夠根據具體需求修改此值。

修改 UI

下面介紹一種很是實用的命令,那就是使用斷點來調試 UI 問題。在平常開發中,咱們會常常微調一些 UI 樣式,每次修改再從新編譯運行是很是浪費時間的,咱們能夠經過 LLDB 來實現改完不運行便可看見效果。

好比咱們想要修改self.view的某個子控件的位置,咱們可使用下面的命令來打印出self.view的全部子控件的詳細信息。

//格式:expression -l objc -O -- <expr>
// - 打印self.view 的子視圖
expression -l objc -O -- [`self.view` recursiveDescription]
複製代碼

經過上面的命令咱們能夠拿到須要修改控件的內存地址,而後再用下面的命令來修改子控件的 frame :

//格式: unsafeBitCast(point, to: type)
//第一個參數爲子控件的內存地址,第二個參數爲子控件的類型。

// - 將一個UIButton的實例的x賦值爲100
expression unsafeBitCast(0x7fa94cb015c0, to: UIButton.self).frame.origin.x = 100
複製代碼

將子控件的內存地址修改以後,咱們能夠經過如下命令來刷新暫存區,看見實際的效果,而不是經過從新運行。

//刷新暫緩區 
expression CATransaction.flush()
複製代碼

Note - 設置別名

上面的命令很長,咱們每次都這麼輸入很麻煩,咱們能夠也能夠設置別名來使用。

//設置別名
commend alias 別名 原命令
//這樣就可使用 flush 來代替 expression CATransaction.flush()
command alias flush expression -l objc -- (void)[CATransaction flush]
複製代碼

p po frame

p/po: 無實質性的區別,看你本身須要的格式使用。
frame: 直接從內存中獲取,輸出 LLDB 的格式。
複製代碼
  • p/po 不能使用的時候,frame應該能使用
  • 在Xcode10.2 中,新添加了v/vo來替代p/po,具體詳情可參見這裏

總結

  • LLDB 表達式能夠修改代碼的狀態
  • 經過thread jump --by 1跳過代碼
  • 使用 Obj-c 的代碼在 Swift 的框架中:expression -l objc -O -- <expr>
  • 刷新視圖暫存區:CATransaction.flush()
  • 設置別名:
command alias poc expression -l objc -O --
command alias flush expression -l objc -- (void)[CATransaction flush]
複製代碼

參考

相關文章
相關標籤/搜索