Xcode 除錯方法總結
前言:編寫程式碼過程中出現錯誤、異常是不可避免的。通常我們都需要進行大量的除錯去尋找、解決問題。這時,熟練掌握除錯技巧將很大程度上的提高工作效率。接下來就說說開發過程中Xcode的除錯方法。
1. Enable NSZombie Objects (開啟殭屍物件)。
這個技巧主要用來追終重複釋放的問題。個人認為,ARC推出以來。專案的基本是基於ARC環境。不用開發者主動去呼叫release去釋放物件,所以不用太在意這個方法。這裡就不多做介紹了。想了解該方法的同學請 坐飛機
2. 斷點除錯(全域性斷點、條件斷點)
一、全域性斷點:
NSArray *aa = @[@2,@4];
NSLog(@" %@",aa[3]);
這兩行程式碼,沒有新增全域性斷點時,執行crash,直接就跳到了mian函式,如下圖:
接下來新增全域性斷點,方法如下圖:
新增之後執行,奔潰後,程式停留在了crash那行程式碼。
是不是很方便,很省事。哈哈!(ps 不過有的crash,這種方式定位不到)
二、條件斷點:設定斷點觸發的條件,方便開發者對特定情況進行除錯
如下圖:
在for迴圈中新增一個斷點。右擊斷點選擇”Edit BreakPoint”,然後設定斷點觸發條件。
這個例子當 “i==5”時,斷點觸發,如下圖:
3. Static Analyzer (靜態分析)
Static Analyzer主要用於分析記憶體,避免記憶體洩漏。主要對以下情況進行分析。
未使用的例項變數、未初始化的例項變數、型別不相容、無法達到的路徑、引用空指標
使用:command + shift +B,如下圖就能輕鬆找到可能記憶體洩漏的程式碼,然後我們根據程式碼環境進行修復就可以了(ps:有的記憶體洩漏可能檢測不出來,還是需要我們在寫程式碼時對記憶體這塊多留點心。)
4. LLDB偵錯程式
這個方法是我今天主推的方法。比較高階,也更加靈活、方便。
隨著Xcode5,LLDB偵錯程式已經取代了GDB,成為了Xcode工程中預設的偵錯程式。其實Xcode已經幫我們完成了大部分工作,而且很多東西也可以在Xcode中直接看到。所以這裡我們只列舉常用的命令。
列印:p,print的縮寫:該命令如果列印的是簡單型別則會列出簡單型別的的型別和值,如果是物件會打印出物件的地址。
po,print Object 的縮寫,用於輸出OC物件
如下如,當執行到斷點處時,控制檯就會出現LLDB的除錯命令列。我們只需在這裡進行除錯。
expr:expression的縮寫,可以在除錯時動態執行指定表示式,並將結果打印出來。常用於在除錯過程中修改變數的值。
如上圖,你在控制檯輸入
expr a=2
你就能看到
(NSInteger) $11 = 2
這是a的值就被動態改成了2
除此之外,還可以使用這個命令生成一個新的物件,如:
expr int $b = 0
p $b
這條命令用於輸出新申明物件的值(注意要加$)
image: image命令可用於定址,有多個組合命令,在控制檯輸入help image
可檢視image的用法。比較實用的用法是用於尋找棧地址對應的程式碼位置,下面我們來舉個例子:
NSArray *array = @[@1,@2];
NSLog(@"%@",array[2]);
這段程式碼很明顯會crash,執行之後丟擲下面的異常
2016-03-23 22:26:11.014 Test[3631:136626] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayI objectAtIndex:]: index 2 beyond bounds [0 .. 1]'
*** First throw call stack:
(
0 CoreFoundation 0x0000000104f28f45 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x00000001049a2deb objc_exception_throw + 48
2 CoreFoundation 0x0000000104e17b14 -[__NSArrayI objectAtIndex:] + 164
3 Test 0x00000001044a5829 -[ViewController viewDidLoad] + 265
4 UIKit 0x0000000105467cc4 -[UIViewController loadViewIfRequired] + 1198
5 UIKit 0x0000000105468013 -[UIViewController view] + 27
6 UIKit 0x000000010534151c -[UIWindow addRootViewControllerViewIfPossible] + 61
7 UIKit 0x0000000105341c05 -[UIWindow _setHidden:forced:] + 282
8 UIKit 0x00000001053534a5 -[UIWindow makeKeyAndVisible] + 42
9 UIKit 0x00000001052cd396 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 4131
10 UIKit 0x00000001052d39c3 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1750
11 UIKit 0x00000001052d0ba3 -[UIApplication workspaceDidEndTransaction:] + 188
12 FrontBoardServices 0x0000000107c83784 -[FBSSerialQueue _performNext] + 192
13 FrontBoardServices 0x0000000107c83af2 -[FBSSerialQueue _performNextFromRunLoopSource] + 45
14 CoreFoundation 0x0000000104e55011 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
15 CoreFoundation 0x0000000104e4af3c __CFRunLoopDoSources0 + 556
16 CoreFoundation 0x0000000104e4a3f3 __CFRunLoopRun + 867
17 CoreFoundation 0x0000000104e49e08 CFRunLoopRunSpecific + 488
18 UIKit 0x00000001052d04f5 -[UIApplication _run] + 402
19 UIKit 0x00000001052d530d UIApplicationMain + 171
20 Test 0x00000001044a5baf main + 111
21 libdyld.dylib 0x000000010764c92d start + 1
22 ??? 0x0000000000000001 0x0 + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException
現在我懷疑出錯的地址是0x00000001044a5829
(可根據執行檔名或最小的棧地址判斷)為進一步精確定位我們可輸入以下命令image lookup --address 0x00000001044a5829
命令執行後返回結果如下:
Address: Test[0x0000000100001829] (Test.__TEXT.__text + 265)
Summary: Test`-[ViewController viewDidLoad] + 265 at ViewController.m:21
由此,我們可以看出出錯的地方是ViewController.m檔案的第21行。
我們還可以使用image lookup命令檢視具體的類,如下:
(lldb) image lookup --type UIView
Best match found in /Users/jamalping/Library/Developer/Xcode/DerivedData/Test-gviuudbzlyhssmanjxpwhchdbscz/Build/Products/Debug-iphonesimulator/Test.app/Test:
id = {0x00001e8d}, name = "UIView", byte-size = 8, decl = UIView.h:144, clang_type = "@interface UIView : UIResponder
@property ( getter = isUserInteractionEnabled,setter = setUserInteractionEnabled:,assign,readwrite,nonatomic ) BOOL userInteractionEnabled;
@property ( getter = tag,setter = setTag:,assign,readwrite,nonatomic ) NSInteger tag;
@property ( readonly,getter = layer,setter = <null selector>,nonatomic ) CALayer * layer;
@property ( readonly,getter = isFocused,setter = <null selector>,nonatomic ) BOOL focused;
@property ( getter = semanticContentAttribute,setter = setSemanticContentAttribute:,assign,readwrite,nonatomic ) UISemanticContentAttribute semanticContentAttribute;
@end
"
call
call:即呼叫,如我們在viewDidLoad:
設定一個斷點,在程式中斷的時候輸入call self.view.backgroudColor = [UIColo redColor]
繼續執行程式,view就變成紅色了,在除錯的時候靈活運用call命令可以達到事半功倍的效果。