1. 程式人生 > >xcode除錯之斷點除錯及動態輸出

xcode除錯之斷點除錯及動態輸出

   在開發App的過程中,需要反覆的修改和優化我們的程式碼,特別是當程式出現bug,需要快速的找出錯誤的原因,進行修改,以保證程式的正確執行。
斷點除錯,是最常用最簡單的一種除錯方式,可以一步步跟蹤程式執行的流程,得到變數的值,快速的找到錯誤的原因。

1、斷點的基本操作

  一,斷點的設定 

 斷點的操作非常簡單,下面通過幾張圖來介紹一下如何新增、刪除、編輯以及使用斷點。設定斷點也可以通過快捷鍵(command+"\")在需要設定斷點的程式碼處




二,斷點的自定義

(1)在你設定斷點的地方,右擊該斷點,會彈出一個欄,選擇Edit Breakpoint,可以對斷點進行自定義設定


(2)點選Edit Breakpoint選項後,彈出如下圖


藍色對勾:藍色對勾後面表示,當前斷點所處的位置將對勾抹去,表示該斷點失效。(程式碼行數顯示你可以在選單欄Xcode->Preferences->TestEditing->勾選Line Numbers,將程式碼行數字顯示出來。)

Condition:指的是條件表示式,該項允許我們對斷點生效設定條件,表示當滿足某一特定條件的前提下,該斷點才生效。(該條件的錄入,不能夠識別預處理的巨集定義,也不能識別斷點作用域之外的變數和方法)。
Ignore忽略次數。它指定了在斷點生效,應用暫停之前,程式碼忽略斷點的次數。你如果希望應用執行一段時間後斷點才生效,那麼就可以使用這個選項。比如說在除錯某一迴圈體的時候。


Action:動作。它表示當斷點生效時,Xcode作出反應後的行為動作。點選右邊的Add Action選項會彈出如圖下選單。



圖中所示紅色方框中的選項,可以讓你指定那一種動作。預設的是Debugger Command。還有以下幾種動作供選擇,下面逐一介紹。

1.AppleScript
它是蘋果提供的一種指令碼語言,用來執行一些預先指定的行為。選中該選項,將會出現如下圖所示的AppleScript語言的輸入框。

我在輸入框中輸入了相關的列印資訊,它的意思是彈出一個顯示“Hello World!”的對話方塊。點選Compile按鈕後,如果沒有錯誤,會顯示成功資訊。而點選Test按鈕,會測試執行效果,如下圖



至於紅色方框中的內容是三種特殊符號相對應的定義。

符號標記 定義
@[email protected] LLDB表示式
%B 斷點的名稱
%H 遇到該斷點的次數
2.Capture GPU Frame
這個功能用於當斷點生效時,捕獲GPU當前所繪製的幀。該功能是輔助圖形除錯的。
3.Debugger Command
預設的選項,可以讓斷點執行LLDB除錯命令。
4.Log Message
使用Log命令可以生成訊息佇列,將相關的訊息輸出到控制檯上,還有一個Speak Message選項,可以播報訊息。
5.Shell Command
該動作接收一個命令檔案和引數列表。如下圖

命令檔案必須是一個可執行的二進位制程式或者指令碼。可以複製貼上輸入路徑,也可以點選Choose按鈕選擇具體檔案。
引數通過空格表示分割,也可以在兩個@字元之間包含LLDB表示式。
一般情況下,Xcode會非同步執行Shell Command,也就是說,Shell Command 和偵錯程式將會同步執行。如果希望偵錯程式在Shell Command命令完成後執行,則可以勾選下面的Wait until done選項。
6.Sound
動作會在斷點被觸發時,彈出聲音提示。

2、全域性斷點

  設定全域性斷點(異常斷點),當遇到錯誤,Debug程式會自動定位到棧底資訊,即跳到出錯程式碼所在行。

 

Exception:選項可以讓你選擇響應Objective-C物件丟擲的異常,也可以選擇響應C++物件丟擲的異常。
Break:則是選擇斷點所接收的異常,是接收“Throw”語句丟擲的異常還是Catch語句的。

3、條件斷點

  設定條件斷點,當滿足條件的時候,才觸發斷點,適合用於迴圈結構中,可以準確的定位到某次迴圈。



4、符號斷點

  符號斷點可以中斷指定函式的呼叫,也可以定位到出現異常的程式碼處,並列印異常資訊。

一,設定方法

 

二,通過 ObjC_exception_throw 定位到異常丟擲的位置


三,unrecognized selector send to instancd 快速定位

在Symbolic中填寫如下方法簽名  -[NSObject(NSObject)  doesNotRecognizeSelector:]  


四,新增指定的方法為斷點,比如新增一個 viewDidLoad Symbol


如果你要新增某個特定類的例項方法,可以用 -[類名 例項方法名]。類方法是+[類名   方法名]


5.OpenGL ES錯誤斷點(OpenGL ES Error BreakPoint)

  這個斷點的作用和異常斷點類似,只不過這個斷點只有在openGL ES錯誤發生的時候才會觸發。

6、NSLog輸出

  在除錯的過程中,經常通過NSLog在控制檯輸出需要的資訊。NSLog輸出比較消耗系統資源,輸出的資料也可能會暴露出App裡的保密資訊,所在在釋出正式版本之前必須把所有的NSLog輸出都遮蔽掉。

  NSLog除了輸出基本資訊,對於結構體也可以一次性輸出。



7、動態輸出(lldb)

  在程式的除錯過程中,除了通過斷點除錯在Xcode下方檢視變數的值,也可以通過NSLog在控制檯輸出想要的資訊。使用NSLog輸出需要在執行前就把想要輸出的資訊寫好,如果有改變,需要重新編譯執行,效率非常低。

LLDB 是一個有著 REPL 的特性和 C++ ,Python 外掛的開源偵錯程式。LLDB 繫結在 Xcode 內部,存在於主視窗底部的控制檯中。偵錯程式允許你在程式執行的特定時暫停它,你可以檢視變數的值,執行自定的指令,並且按照你所認為合適的步驟來操作程式的進展。

        GDB to LLDB 參考是一個非常好的偵錯程式可用命令的總覽 當然你也可以通過在輸入臺,鍵入Help命令,檢視相關的除錯命令

     Help

  它會列舉出所有的命令。如果你忘記了一個命令是做什麼的,或者想知道更多的話,你可以通過 help <command> 來了解更多細節,例如 help print 或者 help thread。如果你甚至忘記了help 命令是做什麼的,你可以試試 help help。

例如:

lldb  help


lldb  help print


 print 

   就是列印值    LLDB 實際上會作字首匹配。所以你也可以使用 prin,pri,或者 p。但你不能使用 pr,因為 LLDB 不能消除和 process 的歧義 
   你可能還注意到了,結果中有個 $0。實際上你可以使用它來指向這個結果。試試 print $0 + 7,你會看到 106。任何以美元符開頭的東西都是存在於 LLDB 的命名    空間的,它們是為了幫助你進行除錯而存在的。

   

1>print ,po 與expression的關係
考慮一個有意思的表示式:p  count = 18。如果我們執行這條命令,然後列印 count 的內容。我們將看到它的結果與expression   count = 18 一樣。
expression 不同的是,print 命令不需要引數。比如 e   -h +17 中,你很難區分到底是以-h 為標識,僅僅執行+17 呢,還是要計算17h 的差值。連字元號確實很讓人困惑,你或許得不到自己想要的結果。
幸運的是,解決方案很簡單。用 -- 來表徵標識的結束,以及輸入的開始。如果想要-h 作為標識,就用e -h -- +17,如果想計算它們的差值,就使用e -- -h +17。因為一般來說不使用標識的情況比較多,所以 e -- 就有了一個簡寫的方式,那就是print
輸入 help print,然後向下滾動,你會發現:
'print' is an abbreviation for 'expression --'.   
(print是 `expression --` 的縮寫)

列印物件
嘗試輸入
p objects
輸出會有點囉嗦
(NSString *) $7 = 0x0000000104da4040 @"red balloons"
如果我們嘗試列印結構更復雜的物件,結果甚至會更糟
(lldb) p   @[ @"foo", @"bar" ]
(NSArray *) $8 = 0x00007fdb9b71b3e0 @"2 objects" 

實際上,我們想看的是物件的 description 方法的結果。我麼需要使用 -O (字母 O,而不是數字 0) 標誌告訴 expression 命令以 物件 (Object) 的方式來列印結果。
(lldb) e -O -- $8
<__NSArrayI 0x7fdb9b71b3e0>(
foo,
bar
)

幸運的是,e -o -- 有也有個別名,那就是po (print object 的縮寫),我們可以使用它來進行簡化:

(lldb) po $8
<__NSArrayI 0x7fdb9b71b3e0>(
foo,
bar
)
(lldb) po @"lunar"
lunar
(lldb) p @"lunar"
(NSString *) $13 = 0x00007fdb9d0003b0 @"lunar"
2>列印變數
可以給 print 指定不同的列印格式。它們都是以 print/<fmt>或者簡化的p/<fmt> 格式書寫。下面是一些例子:
預設的格式
(lldb) p 16
16
十六進位制:
(lldb) p/x 16
0x10
二進位制 (t 代表 two):
(lldb) p/t 16
0b00000000000000000000000000010000
(lldb) p/t (char)16
0b00010000
你也可以使用 p/c 列印字元,或者 p/s 列印以空終止的字串 (譯者注:以 '\0' 結尾的字串)。

列印物件(po)

     (lldb) po anObj 
     (lldb) po 0x0715aa40 

  po用於列印輸出物件資訊。使用動態指令需要與斷點配合使用,這樣就能夠動態的列印輸出程式執行到某個斷點時的資訊。


打印表達式(expr)

expo:可以在除錯時動態執行指定表示式,並將結果打印出來。常用於在除錯過程中修改變數的值。LLDB 實際上會作字首匹配。所以你也可以使用 e

     (lldb) expr 5+2 
     (lldb) e aString = @"aNewValue" 

列印呼叫堆疊(bt)

列印呼叫堆疊,加all可列印所有thread的堆疊。

查詢地址(image)

image 命令可用於定址,有多個組合命令。比較實用的用法是用於尋找棧地址對應的程式碼位置。 下面我寫了一段程式碼

NSArray *arr=[[NSArray alloc] initWithObjects:@"1",@"2", nil];
NSLog(@"%@",arr[2]);
這段程式碼有明顯的錯誤,程式執行這段程式碼後會丟擲下面的異常:
*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:(
  0   CoreFoundation                      0x0000000101951495 __exceptionPreprocess + 165
  1   libobjc.A.dylib                     0x00000001016b099e objc_exception_throw + 43
  2   CoreFoundation                      0x0000000101909e3f -[__NSArrayI objectAtIndex:] + 175
  3   ControlStyleDemo                    0x0000000100004af8 -[RootViewController viewDidLoad] + 312
  4   UIKit                               0x000000010035359e -[UIViewController loadViewIfRequired] + 562
  5   UIKit                               0x0000000100353777 -[UIViewController view] + 29
  6   UIKit                               0x000000010029396b -[UIWindow addRootViewControllerViewIfPossible] + 58
  7   UIKit                               0x0000000100293c70 -[UIWindow _setHidden:forced:] + 282
  8   UIKit                               0x000000010029cffa -[UIWindow makeKeyAndVisible] + 51
  9   ControlStyleDemo                    0x00000001000045e0 -[AppDelegate application:didFinishLaunchingWithOptions:] + 672
  10  UIKit                               0x00000001002583d9 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 264
  11  UIKit                               0x0000000100258be1 -[UIApplication _callInitializationDelegatesForURL:payload:suspended:] + 1605
  12  UIKit                               0x000000010025ca0c -[UIApplication _runWithURL:payload:launchOrientation:statusBarStyle:statusBarHidden:] + 660
  13  UIKit                               0x000000010026dd4c -[UIApplication handleEvent:withNewEvent:] + 3189
  14  UIKit                               0x000000010026e216 -[UIApplication sendEvent:] + 79
  15  UIKit                               0x000000010025e086 _UIApplicationHandleEvent + 578
  16  GraphicsServices                    0x0000000103aca71a _PurpleEventCallback + 762
  17  GraphicsServices                    0x0000000103aca1e1 PurpleEventCallback + 35
  18  CoreFoundation                      0x00000001018d3679 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 41
  19  CoreFoundation                      0x00000001018d344e __CFRunLoopDoSource1 + 478
  20  CoreFoundation                      0x00000001018fc903 __CFRunLoopRun + 1939
  21  CoreFoundation                      0x00000001018fbd83 CFRunLoopRunSpecific + 467
  22  UIKit                               0x000000010025c2e1 -[UIApplication _run] + 609
  23  UIKit                               0x000000010025de33 UIApplicationMain + 1010
  24  ControlStyleDemo                    0x0000000100006b73 main + 115
  25  libdyld.dylib                       0x0000000101fe95fd start + 1
  26  ???                                 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
現在,我們懷疑出錯的地址是0x0000000100004af8(可以根據執行檔名判斷,或者最小的棧地址)。為了進一步精確定位,我們可以輸入以下的命令:
image  lookup  -- address  0x0000000100004af8
命令執行後返回:
Address: ControlStyleDemo[0x0000000100004af8] (ControlStyleDemo.__TEXT.__text + 13288)
Summary: ControlStyleDemo`-[RootViewController viewDidLoad] + 312 at RootViewController.m:53
我們可以看到,出錯的位置是RootViewController.m的第53行。

詳情請考參考這裡

8、殭屍模式

    1. 什麼是 EXC_BAD_ACCESS?

    簡單的說就是,你向一個已經釋放的物件傳送訊息。在c和Objective-c中,我們對記憶體的操作都是通過指標完成的,不是直接對記憶體進行操作指標中儲存的是記憶體地址,通過記憶體地址,我們就能對該儲存區域進行操作。但是,當該儲存器區域不再對映到您的應用時,或者換句話說,該記憶體區域在你認為使用的時候卻沒有使用,該記憶體區域是無法訪問的。 這時核心會丟擲一個異常( EXC ),表明你的應用程式不能訪問該儲存器區域(BAD ACCESS)。一般情況下,EXC_BAD_ACCESS是由被損壞的指標引起的。比如野指標,記憶體洩漏等等

    2.為什麼要了解EXC_BAD_ACCESS

Xcode可以把那些已經release掉得物件,變成“殭屍”,當我們訪問一個Zombie物件時,Xcode可以告訴我們正在訪問的物件是一個不應該存在的物件了,你的應用程式將會由於EXC_BAD_ACCESS而崩潰。因為Xcode知道這個物件是什麼,所以可以讓我們知道這個物件在哪裡,以及這是什麼時候發生的。而Xcode這種能力就是通過殭屍模式來體現的

    3.殭屍除錯模式

單擊左上角的Edit Scheme,並選中Edit Scheme。


在左側選中Run ,在上方開啟 Diagnostics選項。要啟用殭屍物件,勾選 Enable Zombie Objects選框。


如果你現在遇到EXC_BAD_ACCESS ,在Xcode的控制檯輸出,告訴你該從哪裡查詢問題。看看下面的例子輸出。 
2016-07-28 06:31:55.501 Debug[2371:1379247] -[ChildViewController respondsToSelector:] message sent to deallocated instance 0x17579780
這條訊息對於定位問題有很好的提示作用。但是很多時候,只有這條提示是不夠的,我們需要更多的提示來幫助定位問題,這時候再加入 MallocStackLogging 來啟用malloc記錄。



相關推薦

xcode除錯斷點除錯動態輸出

   在開發App的過程中,需要反覆的修改和優化我們的程式碼,特別是當程式出現bug,需要快速的找出錯誤的原因,進行修改,以保證程式的正確執行。 斷點除錯,是最常用最簡單的一種除錯方式,可以一步步跟蹤程式執行的流程,得到變數的值,快速的找到錯誤的原因。 1、斷點的基本操

谷歌瀏覽器除錯工具斷點除錯

     今天跟大家講一下前端中比較常用也是比較重要的一個內用——斷點除錯。 在編寫程式碼的過程中經常要對自己寫的js程式碼進行除錯。 先點選F12進入瀏覽器的除錯。 ps: 原生代碼支援動態修改 單步執行過程中,滑鼠選中邏輯語句,可以檢視最終的運算結果

Fiddler操作具體實踐斷點除錯

一.通過斷點可以實現的結果 1.修改http請求頭資訊,如請求頭的UA,cookie,refererder資訊 2.構造請求資料,突破錶單的限制,隨意提交資料。避免頁面JS和表單限制影響相關除錯。 3.攔截響應資料,修改響應實體。 二.兩種方法設定斷點 1.Fiddle

移動端Web開發除錯Weinre除錯教程

在設計師與前端開發人員的努力下,一個WebApp出爐了,可是測試人員說了一堆的問題:某某機型下頁面表現不一致,某某系統下頁面如何如何,某某系統瀏覽器下頁面怎麼怎麼滴。看著滿滿的測試彙總文件,我們曾經在一個又一個知名或不知名的手機終端上重複著這些工作:仔細的排查程式碼,alert可疑的變數,甚至不惜重

iOS探索:Runtime訊息轉發動態新增方法

在開始之前,我們先來了解下OC中的類與物件 這是一張經典的類的關係示意圖,接下來簡單的介紹一下這張圖 首先當我們建立一個實力物件,會拷貝這個實力物件所屬類的成員變數,但是不會拷貝類定義的方法 當我們傳送訊息給例項物件時,會通過這個例項物件中的isa指標去找到它對應的類,在

瀏覽器除錯js除錯

現在的瀏覽器一般都給了我們除錯js的功能,個人比較推薦使用google瀏覽器,他的除錯結構清晰且強大,下面就來介紹一下google瀏覽器的除錯功能 偵錯程式介面 按下F12,你會發現彈出來一個視窗,並附著在當前頁面,這就是google瀏覽器

動態除錯——x64dbg的使用

首先x64dbg如何下載,這個還要我說的話,別玩電腦了,我用x64dbg開啟一個程式 如圖,我圈起來的地方,你看是不是都是7開頭的,這個叫做系統領空,是系統的程式碼段,你不用去改他,改他也沒用,沒法儲存,我們除錯程式,需要到程式的領空,所以,這個沒啥用,如何進入到程式領

動態規劃揹包問題輸出揹包具體方案

參考:https://blog.csdn.net/qq_27139155/article/details/79727991 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N=20; 4 int n,b;

音訊處理回聲消除除錯經驗

本文講的回聲(Echo)是指語音通訊時產生的回聲,即打電話時自己講的話又從對方傳回來被自己聽到。回聲在固話和手機上都有,小時還可以忍受,大時嚴重影響溝通交流,它是影響語音質量的重要因素之一。可能有的朋友要問了,為什麼我打電話時沒有聽見自己的回聲,那是因為市面上的成熟產品回聲都被消除掉了。回聲分為線路回聲(li

PL\SQL 動態執行表不可訪問,本會話的自動統計被禁止,無法斷點除錯 的解決方法

PL\SQL 使用普通使用者用登陸,在操作oracle時可能出現"動態執行表不可訪問,本會話的自動統計被禁止"錯誤解決,無法斷點除錯procedure的告警,需要賦予使用者以DBA許可權,或普通用賦予以下許可權, grant select on v_$statname to

平衡車mpu6050除錯問題總結

這裡重點講解AD0的作用,I2C通訊中從機是要有地址的,以區別多個從機。當AD0管腳接低電平的時候,從機地址是0x68。從MPU6050的暫存器中我們可以得到答案,MPU6050作為一個IIC從機裝置的時候,有8位地址,高7位的地址是固定的,就是WHOAMI暫

除錯遞迴函式除錯思考.

除錯之思考以及遞迴函式除錯之思考! ------------------------------------------------------------ author: hjjdebug date: 2017年 12月 27日 --------------------

C++動態除錯斷點無效,提示資訊:當前不會命中斷點,還沒有為該文件載入任何符號

在對C#呼叫的C++動態庫打斷點進行除錯時,斷點變為黃色感嘆號,未進入斷點,反覆查詢原因,重新生成的dll檔案已經拷貝到C#相關目錄下面,但還是無法進入斷點,後來發現重新生成的動態庫的pdb檔案沒有拷貝到C#相關目錄下面,對動態庫進行清理,重新生成解決方案,然後將新生成的dl

【Android Studio簡易教程】斷點除錯相關技巧

一 斷點除錯流程 下面我們用一個例項來演示斷點除錯的流程和相關技巧。 本例中我們用斷點除錯跟蹤一個for迴圈中,迴圈變數i的數值變化,如下所示: Shift+F9進入Debug除錯,程式執行後就可以檢視Debug面板,我們可以在面板裡實時檢視各

DELPHI 2010 動態連結庫DLL斷點除錯

DELPHI 2010 動態連結庫DLL斷點除錯 馬根峰 (廣東聯合電子服務股份有限公司,廣州 510300) 摘要:本文詳細介紹了Delphi 2010中的動態連結庫DLL斷點除錯技術 關鍵詞:DELPHI 2010;Dll斷點除錯; 1Delphi幾個經典版

linux cgdb常用斷點除錯總結

1 、安裝GDB sudo apt-get install gdb 2 、怎麼打斷點 1 、原始檔的某一行設定斷點 break 行號 2、一個特定的函式設定斷點 break 函式名 3、設定條件斷點 break 行號 if 條件 3、舉例分析 hello2.

Linux 作業系統 C 語言程式設計入門編譯除錯說明Makefile的編寫

1.C語言編譯和除錯說明: sourefile: main.c 編譯:將原始檔編譯成目標檔案--->gcc -c main.c 將目標檔案編譯成可執行檔案--->gcc -o main m

kernel檔案動態除錯功能 -- dynamic_debug 開啟半閉

Kernel def_config中需要開啟以下兩個巨集 CONFIG_DEBUG_FS=y CONFIG_DYNAMIC_DEBUG=y (1)step1:open pr_debug adb root adb remount adb shell 開啟動態除錯

Android學習探索App多渠道打包動態添加修改資源屬性

Android App 前言: 關於Android渠道打包是一個比較老的話題,今天主要記錄總結一下多渠道打包以及如果動態配置修改一些資源屬性。今天以公司實際需求為例進行演示,由於項目復用很多公共的業務組件,而且業務組件之間的跳轉采用Scheme協議,每個業務組

IOS調試—斷點調試以及動態輸出

屏蔽 ont div 動態 medium 出錯 http 對象 版本 在開發App的過程中。須要重復的改動和優化我們的代碼,特別是當程序出現bug,須要高速的找出錯誤的原因,進行改動,以保證程序的正確運行。   斷點調試,是最經常使用最簡單的一種調試方式,