- 原文地址:Xcode and LLDB Advanced Debugging Tutorial: Part 3
- 原文做者:Fady Derias
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:kirinzer
- 校對者:swants, iWeslie
在這三部分教程的第一部分和第二部分中,咱們已經介紹瞭如何利用 Xcode 斷點來控制一個存在的屬性值,而且經過表達式語句注入新的代碼行。咱們還探索了觀察點這種特殊類型的斷點。前端
我開發了一個特地帶有幾個錯誤的演示項目,詳細說明了如何使用不一樣類型的斷點配合 LLDB 來修復項目/應用程序中的錯誤。android
若是你尚未看過本教程的 第一部分 和 第二部分,最好先看過它們再繼續閱讀本文。ios
最後,本教程的指導原則是:git
第一次運行應用程序後,你沒必要中止編譯器或從新運行應用程序,你將在運行時修復這些錯誤。github
到目前爲止咱們還要作什麼?express
- 導航欄左側指示用戶加載次數的標籤沒有更新。
這裏有一些步驟能夠復現這最後一個須要處理的錯誤:json
✦ 滾動到表視圖的頂部,而後下拉刷新。後端
✦ 滾動到表視圖的底部去加載更多文章。[7 次 😉]xcode
✦ 在每次成功獲取到新的文章以後,左側標籤並無被更新。bash
須要指出的是整型屬性 pageNumber
回答了這個問題,用戶已經加載了文章多少次?(換句話說,導航欄左側的標籤應該被 pageNumber
屬性的值更新)。咱們能夠確信的是,在以前的修復中 pageNumber
屬性的值已經能夠更新了。所以如今的問題在於沒有將它的值設置給導航欄左側的標籤。
在這種狀況下,符號斷點會介入。想象一下,符號斷點就像調試器在玩尋寶,而你會提供一些尋寶的線索。對你來講,這會發生在更新導航欄左側標籤的代碼片斷中。
讓我告訴你接下來怎麼作。
展開 Breakpoint navigator,接着點擊左下角 + 按鈕,選擇 Symbolic Breakpoint。
在 Symbol 欄添加以下符號
[UILabel setText:]
複製代碼
不要 勾選 「Automatically continue after evaluating actions」 選項框。
咱們所作的只是告訴調試器,當任何一個 UILabel 的 setText 方法被調用的時候,它就會暫停。注意這裏在建立了一個符號斷點以後,一個子斷點會被添加。
這是來自調試器的反饋,它可以解析這個建立的符號斷點到 UIKitCore
框架的特定位置。在其餘狀況下,調試器也許會解析到多個位置。
如今一切就緒,下拉以刷新表視圖的文章。當你釋放以後,調試器就會暫停,接着你會看到以下圖的東西:
在這時你會看到一些 UIKitCore 框架的彙編代碼,在左側的是致使調試器暫停的堆棧信息。下一步咱們要作的是,檢查在調試器暫停的位置傳入 Objective-C 消息的參數。在 lldb 控制檯輸入下面的命令:
po $arg1
複製代碼
這會指出持有第一個參數的寄存器。咱們能清楚的看到接受這個 Objective-C 消息的是一個 UILabel 實例。這個 UILabel 實例有一個文本值指向一個文章的標籤。這不是咱們所感興趣的,不過讓咱們繼續寄存器檢查。
在 lldb 控制檯,輸入以下指令:
po $arg2
複製代碼
$arg2 始終指向 Objective-C 消息的選擇器。在某些狀況下,lldb 並不徹底的清楚參數的類型,所以咱們須要作一些類型轉換的工做。
在 lldb 控制檯,輸入以下指令:
po (SEL)$arg2
複製代碼
如今咱們很清楚的看到了當前 Objective-C 消息的選擇器。
在 lldb 控制檯,輸入以下指令:
po $arg3
複製代碼
$arg3 始終指向傳入方法的第一個參數。在咱們的情形下,傳入 setText 方法的參數一個字符串。
繼續執行程序。調試器會再次暫停。重複前面的步驟,最終,你發現這個 Objective-C 消息屬於在表視圖裏的另外一個文章標籤。直到咱們找到咱們感興趣的那個 UILabel 實例前,一遍又一遍的作這個事情確實很無趣。確定有更好的方式。
你可以作的一件事就是爲符號斷點設置條件,以便在成功或知足條件時暫停調試器。它可以檢查布爾值或者等待條件達成諸如此類。
然而,咱們採用一種不一樣的方法。
將咱們建立的符號斷點設置爲不可用。
講道理,導航欄左側的標籤指示了用戶加載文章的次數,它會在 HTTP GET 請求成功完成以後被更新。找到有 pragma mark Networking
的部分。在 loadPosts
成功完成的回調裏放置一個斷點。這個斷點應該放在以下的位置:
Objective-C
[self.tableView reloadData];
複製代碼
Swift
self.tableView.reloadData()
複製代碼
這會確保符號斷點只有在表視圖從新加載數據以後纔會被觸發,全部相等的標籤都已經被更新。
不要 勾選 「Automatically continue after evaluating actions」 選項框。添加以下的調試器命令動做:
breakpoint set --one-shot true -name '-[UILabel setText:]'
複製代碼
🤨🧐🤔
讓咱們拆解這個命令:
breakpoint set --one-shot true 會建立一個 「one-short」 斷點。one-shot 斷點是一種建立以後,首次觸發就會自動刪除的斷點。
-name ‘- [UILabel setText:]’
給建立的 one-shot 斷點設置了一個符號名。這和你上一節所作的很是類似。
讓我總結一下這一部分。你所作的有:
在發起 GET 請求成功完成的回調裏添加斷點(A)。
添加調試器命令動做去 建立 符號斷點(B)和上一節建立的很類似。這個符號是 UILabel
setText
方法。
將你建立的符號斷點(B)設置爲一個 one-shot 斷點。one-shot 斷點在觸發後會被自動刪除,這意味着符號斷點只會暫停調試器一次。
斷點(A)被放置在表視圖加載完成以後,所以建立的符號斷點(B)不會因任何和表視圖相關聯的標籤而暫停調試器。
如今下拉表視圖去刷新。咱們會獲得以下內容:
因爲設置了 one-shot 斷點調試器停在了斷點(A)的位置。
繼續執行程序。
你會返回到 UIKitCore 框架的彙編代碼。
讓咱們檢查一下符號斷點參數的 Objective-C 消息。
在 lldb 控制檯,輸入以下的指令:
po $arg1
複製代碼
哇哦,看起來你找到了寶藏! 🥇🏆🎉
是時候把咱們的目光轉移到堆棧跟蹤信息了。走到點 1 的位置。
它會引導你到這塊更新 pageNumberLabel
文本的代碼。這塊代碼很明顯爲文本始終設置了整型值爲 0
而不是 pageNumber
屬性的格式字符串。讓咱們在實際修改代碼前先測試一下。
你如今已是行家了 🧢
在已標記的代碼分隔線下添加一個斷點。添加以下的調試器命令動做:
Objective-C
expression self.pageNumberLabel.text = [NSString stringWithFormat:@"Page %tu", self.pageNumber]
複製代碼
Swift
expression pageNumberLabel.text = String(format: "Page %tu", pageNumber)
複製代碼
移除或者停用斷點(A),相應地,斷點(B)也會被停用。
如今下拉刷新和加載更多文章。左側導航欄標籤將會被更新。 🎉
任務完成! 💪 💪
如今你能夠中止編譯器而且在代碼中去修復咱們討論的這些問題。
在這個教程裏,你學會了
如何使用斷點配合調試器動做表達式去控制存在的屬性值。
如何使用斷點配合調試器動做表達式注入代碼。
如何爲某個屬性設置觀察點監視屬性值的變化。
如何基於定義的符號使用符號斷點暫停調試器。
如何使用 one-shot 斷點。
如何使用 one-shot 斷點配合符號斷點。
調試愉快! 😊
爲了本教程的方便,我使用了下面的第三方工具。
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。