為什麼你的數組包含3個項目而不是5個?為什麼你的遊戲運行緩慢?這些都跟調試有關,調試是開發過程中必不可少的一部分。本文所列舉了一些重要的調試功能(當然並不全面)可以幫你用更少的時間來解決bug問題。
本文內容主要包括3個方面:
使用console檢查app狀態
進行日誌記錄,並熟練的駕馭NSLog
使用對象的生命週期來跟蹤記憶體的使用。
使用Console檢查app狀態Xcode底部的小黑盒是我們調試時的好朋友,它可以輸出日誌資訊、錯誤資訊以及其他有用的東西來幫你跟蹤錯誤,除了可以看到日誌直接輸出的資訊外,我們編程過程中也可以在某些斷點停留,來檢查app的多個方面。
條件斷點我假定你知道Breakpoints是如何工作的(如果你不知道,呵呵,看完這個文章也許你就知道了!) 讓程式在某個特定的時間點命中斷點非常有價值,但要通過一個迴圈或者遞迴函式才能讓對象等於某個確定的值,是一件令人痛苦的事情。這時候我們可以使用條件斷點! 條件斷點就是帶有條件運算式的斷點,只有滿足這個條件,程式才會暫停。假想我們只想在對象處於特定狀態的時候斷點,或者在第N次迭代迴圈時命中斷點。 點擊Xcode editor的‘gutter’來添加斷點,右鍵點擊斷點,然後選擇“edit breakpoint”來設定特定條件。 條件斷點只有在遇到特定情況時才會中斷,你可以提供給一個條件(比如i == 12),或者斷點應該忽略的次數。另外,你還可以添加能根據斷點自動發生的動作,例如一個debugger command---列印一個值。 提示:添加/刪除斷點的鍵盤快速鍵是command+\ 另外一個重要的斷點技巧是添加一個異常斷點(exception breakpoint)。當遇到異常時, Xcode基本上都會自動轉到main方法的autorelease pool中。 通過設定異常斷點,你可以定位到引起異常斷點的具體程式碼。 如何添加異常斷點? 1.開啟異常斷點tab(command+6);2.選擇視窗左下角的”+”按鈕;3.選擇按鈕並添加‘exception breakpoint’。 這樣,當Xcode遇到異常情況時,將會在引起異常代碼的地方發生斷點。
從Console進行手動列印理論上說,它會展示當前環境中所有值的狀態;實際上,有時候會出現bug,並且不會列出值或者當你單步調試的時候不進行更新。 一般情況下,我們在app代碼中添加特定斷點,是為了通過Xcode提供的‘variables view’(該view在Xcode底部console旁邊)來查看對象的狀態 。理論上說,它可以顯示出與當前上下文相關的所有值的狀態。實際上,有時候會有點小問題,不會列出相關的值或者不會進行相關的更新。 不過,我們可以使用一些有用的console命令來檢查特定的對象。在console中輸入‘po’就可以獲得某個斷點的即時資訊。(處理scalar值時,我們可以使用‘p’) 在我們查看一個已存在的對象時,這一點非常有用(如果對象不存在的話會列印出nil),確定對象的值,找出數組/字典運行時的資訊,甚至是比較兩個對象。因為這個指令列印出相關對象的記憶體位址,所以你可以列印你認為應該一樣的兩個對象,看看它們的記憶體位址是否相同。另一個有用的,但是被隱藏的指令是recursiveDescription,你可以簡單地用它對view進行檢查。在view中調用recursiveDescription來列印它的繼承關係。
有效Logging有時,在偵錯工具的某個特定時間,我們希望將訊息列印到控制台,此時‘NSLog’函數允許我們將任意輸出列印至console。 此時可以使用NSLog函數,通過該函數可以將任意的輸出列印到控制台。在不使用斷點時,這個功能非常有用。NSLog遵從的格式與[NSString StringWithFormat]方法遵從的格式一樣。(你可以從下邊的中看到) Tip: 這裡可以看到蘋果關於Objective-C中字串格式化的資訊:
String Programming Guide
NSLog NSLog非常有用,我們需要聰明地實現它。從NSLog列印出的任何東西都會變成代碼,任何人都可以看見。將裝置串連到電腦,開啟XCode中的organiser,就可以從console查看到每條日誌資訊,這會帶來很大的影響。想一下,你想把一些保密的演算法邏輯或者使用者密碼列印到console。正因為這個,如果蘋果發現在production build中,有太多內容輸出到console,那麼你的應用可能會遭到蘋果的拒絕。 幸運的是,這裡有一個最簡單的辦法進行log——通過一個宏,讓NSLog只在debug build的時候起作用。將這個功能添加到全域都能訪問得到的標頭檔中。這樣你就可以盡情的使用log了,並且當進行production時,不會包含log相關代碼。如下代碼: 1.#ifdef DEBUG2.#define DMLog(...) NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])3.#else4.#define DMLog(...) do { } while (0) 如果你使用DMLog,那麼它只能在debug build期間列印。__PRETTY_FUNCTION__ 也可以幫忙列印出log所在的函數的名稱。
下一步
NSLog 很強大,但也有不少限制:1.只能本地列印2.不支援分層級的log(比如是危險還是警告)3.NSLog非常慢,大量處理時會明顯降低程式的運行效率。 推薦兩個架構,可以避免NSLog一些限制:•Cocoa LumberJack –眾所周知的通用的Cocoa日誌架構之一,學習起來有點難度,但是非常強大。•SNLog –NSLog的替代品。
跟蹤對象的生命週期儘管Automatic Reference Counting (ARC)已經讓記憶體管理變得簡單、省時和高效,但是在object的life-cycles中跟蹤一些重要事件依然十分重要。畢竟ARC並沒有完全排除記憶體泄露的可能性,或者試圖訪問一個被release的對象。為了這個目的,我們可以用一些處理方法和工具來協助我們盯著對象正在做些什麼。
LOG重要事件Objective-C 對象的 life-cycle中有兩個很重要的方法: init 和dealloc ,將這兩個方法調用的事件log到console是不錯的選擇——你可以通過控制台觀察到對象生命的開始,更重要的是,可以確保對象的釋放。1.- (id)init2.{3. self = [super init];4. if (self)5. {6. NSLog(@"%@: %@", NSStringFromSelector(_cmd), self);7. }8. return self;9.}10.- (void)dealloc11.{12. NSLog(@"%@: %@", NSStringFromSelector(_cmd), self);13.}
靜態分析器和Inspector(檢查器)Xcode中還有兩個工具可以幫我們清理代碼,減少代碼出錯的幾率。對Xcode而言,靜態分析器工具是一個非常棒用來改善代碼的工具。比如檢測出沒有使用過的對象,沒有release對象(針對Core Foundation對象,ARC仍然會有這樣的問題)。通過選擇Product菜單中的‘Anlayze’可以查看到相關建議。 檢查器是非常強大的一組工具,通過檢查器不僅可以從不同的角度檢查程式對記憶體的使用方式,檔案系統的使用方式(增加、刪除、修改等),甚至還提供了自動UI互動的方法。通過選擇Product菜單中的‘Profile’可以查看到這些檢查器。選擇‘Profile’會開啟一個Instrument視窗,這裡可以選擇一個配置模板進行運行。最常用的模板有zombies(稍後會討論),activity monitor和leaks。在程式運行時,對記憶體泄露進行捕捉時,Leaks可能是最有用的一個模板。
Zombies是你的朋友雖然在有ARC的地方很難再遇到讓人難受的EXC_BAD_ACCESS錯誤了,但是在某些確定的情況下,該錯誤還是會發生的。當在處理UIPopoverController或者core foundation對象時,我們可以訪問一個已經被release掉的對象。一般,當我們release記憶體中的一個對象時,該對象將被銷毀。但是,當Zombies開啟時,只是將對象標記為release,實際上該對象還停留在記憶體中。當我們訪問一個Zombie對象時,Xcode可以告訴我們正在訪問的對象是一個不應該存在的對象了。因為Xcode知道這個對象是什麼,所以可以讓我們知道這個對象在哪裡,以及這是什麼時候發生的。 這裡有兩種方法可以尋找出Zombies對象。使用檢查器中的Zombie配置模板,或者在‘Run’ build選項中開啟Zombie診斷選項。在Stop按鈕的旁邊,點擊scheme名稱,然後選擇‘Edit Scheme’,點擊diagnostic tab項,並勾選上‘Enable Zombie Objects’。注意,Zombie只能用在模擬器調試中,真機上不能使用。 注意,Zombie模式調試僅適用於模擬器,不能在真實裝置上使用。
總結希望以上內容能給你幫你更高效地調試你的app,所有這些都是為了能都節省bug修複時間,這樣開發人員就能把時間花在更重要的事情上,或者打造一款偉大的應用程式。 上邊列出的肯定不是一個全面的列表,還有很多我們沒有討論的方法,比如遠程遙控bug報告,崩潰報告以及更多。也希望你能分享更多。 原文:http://www.cocoachina.com/newbie/basic/2013/0517/6225.htmlby yytong