## 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**:命令別名,用於簡化長命令的輸入。