---
# System prepended metadata

title: '[Video Note] [Xcode] [Debugging] iOS Academy - Debugging in Xcode 13: Tips & Tricks'
tags: [Video Note, Xcode, Debugging]

---

## Intro & Demo
- 在今天的影片中，我們將討論 Xcode 的除錯功能
- 我們會專注於一些中階的技巧，以識別和解決應用程式中的問題
- 開始前，請點讚並訂閱
- 打開 Xcode 並進入一個現有的專案，一個甜點應用程式
- 首先在模擬器中執行應用程式，了解應用程式的基本功能
- 本次影片重點將放在除錯技術和斷點設置上
- 甜點應用程式展示各種甜點和食譜，可瀏覽不同的類別、查看熱門內容、進行搜索等

## Browse Controller
![CleanShot 2024-07-24 at 11.46.28](https://hackmd.io/_uploads/HJ8mKxRuC.png)

- 我們將從 Browse Controller 開始，首先介紹斷點設置
- 斷點設置很簡單，許多人可能已經熟悉
- 在代碼行號上點擊即可設置斷點，應用程式運行到該行時會暫停
- 將斷點設置在第 117 行，當我們在模擬器中點擊頂部的分類按鈕時，會觸發這段代碼
- 點擊分類按鈕，應用程式暫停運行，我們可以在左側面板中看到堆疊幀
- 中間面板顯示彙編代碼，下方的控制台顯示 LLDB 編譯器調試器
- 可以使用 `po` 命令打印對象，比如打印 `vc` 對象，並查看其記憶體地址和屬性
![CleanShot 2024-07-24 at 11.47.40](https://hackmd.io/_uploads/HyTwtlRdC.png)

- 使用 `p` 命令可獲得更詳細的對象信息
![CleanShot 2024-07-24 at 11.48.04](https://hackmd.io/_uploads/SycKYxCuR.png)

- 使用 `frame variable` 命令查看當前幀的變量
![CleanShot 2024-07-24 at 11.48.48](https://hackmd.io/_uploads/HJk3YlAOR.png)

## Breakpoints
- 通過斷點，我們可以在不重新編譯應用程式的情況下注入代碼
- 右鍵或雙擊斷點打開上下文選單，選擇調試命令
- 將斷點移至代碼的適當位置，然後輸入調試命令來更改 `vc.title` 為 "Hello World"
![CleanShot 2024-07-24 at 11.50.09](https://hackmd.io/_uploads/BydZclA_A.png)

- 回到模擬器，點擊運行，檢查變更是否生效
- 設置斷點自動繼續運行，避免每次都手動點擊
- 記得在完成調試後修改實際代碼

## Code Changes
- 簡化代碼變更過程，不需重新編譯應用程式
- 取消斷點設置，設置新的斷點以測試其他代碼區域
- 使用 `expression` 命令進行代碼注入和變更測試
![CleanShot 2024-07-24 at 11.54.02](https://hackmd.io/_uploads/rJ51jgRd0.png)

## Stepping
- 使用步進功能，可以跳過、進入或跳出某行代碼
- 步進功能的按鈕位於 Xcode 下方面板，有詳細說明
- 這些功能可以幫助我們更精確地定位問題
## Debugging Symbols
- 我們的應用程式中有許多符號，例如 `UILabel` 的實例或方法本身。
- 例如，我們有一個方法 `categoryButtonTapped`，假設我們不知道這個方法在應用程式中的具體位置，或者有多個同名方法。
- 要在每次調用這個方法時觸發斷點，可以在左下角選擇斷點圖標，然後點擊加號按鈕。
    ![CleanShot 2024-07-24 at 12.05.53](https://hackmd.io/_uploads/H1gA6gA_A.png)

- 在彈出的選單中，我們選擇符號斷點（Symbolic Breakpoints），然後輸入 `categoryButtonTapped` 作為符號名稱。
    ![CleanShot 2024-07-24 at 12.07.42](https://hackmd.io/_uploads/SJ7QRxAuR.png)

- 設置符號斷點後，Xcode 會嘗試解析應用程式中該符號的位置。
- 若沒有出現任何結果，表示 Xcode 無法找到該符號。
- 這個方法有助於在應用程式中定位特定方法的多個實例。

## Debugging Layout Subviews
- 每個 `UIView` 類別都有一個 `layoutSubviews` 方法，當我們希望每次調用該方法時觸發斷點，可以設置符號斷點。
    ![CleanShot 2024-07-24 at 12.09.26](https://hackmd.io/_uploads/r1m9RxROA.png)

- 這樣一來，每次 `layoutSubviews` 被調用時，斷點都會觸發，無論是在 `UICollectionView` 還是 `UITableView` 的不同單元格上。
    ![CleanShot 2024-07-24 at 12.10.01](https://hackmd.io/_uploads/H1ijRxA_A.png)

- 在執行應用程式時，可以看到這些斷點會多次被觸發，並顯示相應的堆疊跟踪。
- 我們可以逐步查看每個調用的來源，進行深入的調試。

## View Hierarchy & View Debugger
![CleanShot 2024-07-24 at 12.12.30](https://hackmd.io/_uploads/rJ-L1-RuC.png)

- 當應用程式包含許多嵌套的子視圖時，可能會出現視圖重疊或未正確渲染的情況。
- 可以使用 Xcode 的視圖調試器（View Debugger）來檢查視圖層次結構。
- 點擊視圖調試器圖標，會顯示應用程式中所有視圖控制器和 UI 元件的層次結構樹。
- 可以拖動和調整層次結構的顯示，查看不同視圖之間的關係。
- 有時，這種圖形化顯示過於繁瑣，我們只需要在控制台中看到視圖層次結構的遞歸表示。
![CleanShot 2024-07-24 at 12.13.33](https://hackmd.io/_uploads/Sy1Y1WROC.png)

## Recursive Representation
- 要在控制台中打印視圖層次結構，可以使用以下命令：
  ```swift
  expr -l objc -O -- [UIViewController _printHierarchy]
  ```
- 這個命令會打印應用程式中根控制器及其子控制器的層次結構。
- 可以看到每個控制器的詳細信息，例如 `TabBarController` 下的各個 `NavigationController` 和其子控制器。
- 這個方法有助於快速檢查控制器的層次結構，尤其是在應用程式運行過程中動態呈現新的控制器時。

## Alias Commands
- 為了簡化輸入命令的過程，可以使用命令別名（Alias Commands）。
- 例如，可以為打印層次結構的命令設置一個簡短的別名：
  ```swift
  command alias hei expr -l objc -O -- [UIViewController _printHierarchy]
  ```
    ![CleanShot 2024-07-24 at 12.14.07](https://hackmd.io/_uploads/rJQoyb0uC.png)

- 這樣以後只需輸入 `hei` 即可執行該命令。
- 設置別名有助於提高開發效率，減少重複輸入的麻煩。

 
# 關鍵字
- **Breakpoint（中斷點）**：用來暫停程式執行並檢查程式狀態。可以在程式碼的特定行上設定，當程式執行到該行時會暫停。
- **Simulator（模擬器）**：一個虛擬設備，用於在電腦上模擬iOS設備的操作，以便開發者測試應用程式。
- **Stack（堆疊）**：顯示程式執行過程中函數呼叫的順序，幫助開發者理解程式的執行流程。
- **Assembly Code（組合語言代碼）**：低層次的程式碼，顯示程式的底層執行細節。
- **LLDB（LLVM Debugger）**：一種調試工具，用於檢查和修復程式中的問題。可在命令行輸入指令來檢查程式狀態。
- **po（Print Object）**：LLDB中的一個指令，用來打印物件的描述。
- **p**：LLDB中的一個簡寫指令，用來打印物件的更詳細信息。
- **Expression（表達式）**：在調試過程中可以執行的代碼片段，允許開發者在不中斷程式執行的情況下修改變量的值。
- **Frame Variable（框架變量）**：指示當前框架中變量的狀態和值。
- **Step Over（步過）**：調試過程中的一個操作，讓程式執行下一行代碼，但不進入函數內部。
- **Step Into（步入）**：調試過程中的一個操作，讓程式進入並執行函數內部的代碼。
- **Step Out（步出）**：調試過程中的一個操作，讓程式執行完當前函數，返回到調用該函數的地方。 
- **Debugging Symbols（調試符號）**：指的是應用程式中的符號，包含如UI元件（如UILabel）或方法（如categoryButtonTapped）的實例。這些符號幫助開發者識別和定位程式碼中的特定位置。
- **Symbolic Breakpoints（符號中斷點）**：一種中斷點，可以設置在特定的方法或符號上，而不需要具體指明程式碼中的行號。適用於當不知道具體位置或有多個相同名稱的函數時。
- **Layout Subviews（佈局子視圖）**：每個UIView類都有的函數，負責佈局其所有的子視圖。調試此函數有助於解決視圖佈局問題。
- **View Hierarchy（視圖層次結構）**：應用程式中視圖的層次結構，可以用來理解各視圖之間的關係。Xcode提供了視圖層次結構調試器，幫助可視化這些關係。
- **View Debugger（視圖調試器）**：Xcode中的一個工具，用於檢查應用程式的視圖層次結構。可以視覺化並分析視圖的嵌套和佈局。
- **Recursive Representation（遞歸表示）**：在控制台中打印出視圖層次結構的遞歸表示，顯示應用程式中所有視圖的階層和關係。
- **Expression（表達式）**：用於在調試過程中執行代碼片段，允許修改變量值而不重新編譯應用程式。
- **Alias（別名）**：為長命令設定簡短的別名，以便在調試過程中提高效率。 
- **Symbolic Breakpoints**：符號斷點，用於在調試過程中指定特定函數或方法的斷點。
- **UI Label**：用於顯示簡單文本的UI元素。
- **Method**：方法或函數，特定的代碼塊。
- **CategoryButtonTapped**：假設的函數名，表示按下類別按鈕時觸發的函數。
- **UIView**：iOS中的基礎視圖類別，用於構建應用程序的用戶界面。
- **LayoutSubviews**：UIView中的一個方法，用於佈局其子視圖。
- **Breakpoint Icon**：Xcode中設置斷點的圖標。
- **View Hierarchy**：視圖層次結構，表示視圖之間的嵌套關係。
- **View Debugger**：視圖調試工具，用於可視化應用程序的視圖層次結構。
- **Expression**：在調試過程中執行的表達式命令。
- **Objective-C**：一種用於iOS和macOS開發的編程語言。
- **TabBarController**：管理應用程序中多個視圖控制器的選項卡條控制器。
- **Navigation Controller**：管理應用程序中的視圖控制器堆棧的導航控制器。
- **Alias**：命令別名，用於簡化長命令的輸入。
