1. 程式人生 > >XCODE DEBUG 技巧

XCODE DEBUG 技巧

https://www.cnblogs.com/SnowStark/p/5805979.html

抽刀斷Bug


斷點,(我求你們不要想到張敬軒,阿軒他容易麼,小受又怎麼了?你們這幫人真是的!!),我要說的斷點是BreakPoint!基本上不是殘廢的IDE都具有斷點除錯功能吧!尤其是XCode,我們家的IDE斷點除錯功能可是強中又是強中手!在這之前大家可以先了解一下哈子是斷點?它怎麼實現的?工作原理怎麼樣的?博主就獻醜說說自己的理解吧,斷點,顧名思義就是從前有一個點,後來它斷了,謝謝,我的故事講完了。哎喲還不服,這些基礎常識的東西自己不會查?你還真的臉皮厚上天了去了,還要博主給你查喲,自己查去!

普通操作

如圖3

基本的斷點操作如下

圖4

 

點選那個黑列列就建立了一個斷點,再次點選就臨時取消這個斷點(但是不刪除),長按那個斷點拖出去就刪除了(mac os的系統工程師就是稀飯拖動的快感),當然也可以右鍵那個建立的斷點,會彈出相應地選單。
當然也還可以監視某個變數!
圖5

在物件檢視中,右鍵某個物件,點選“Watch ‘XXX’”就完成XXX物件的監視了。

這裡我監視了lab這個UILabel的變數,每當這個變數進行更新它的資訊就會被列印到控制檯。
好吧!我們最基本的建立斷點的工作已經學會了,Xcode舒服在什麼地方呢?就是不分Debug模式和Run模式的,可以說是無縫切換的,你只要沒有建立斷點,那麼就是Run的正常模式,如果建立了斷點並且執行到斷點處,就自動進入Debug模式咯,不像某EC開頭的IDE,控制面板就像開飛機的一樣,幾萬個按鈕以為很強大,其實只用了Run和Stop,還有什麼Debug模式,App模式……,果然Xcode的優越感在對比中更加強烈了,舒服到極點呀,就像夏天的海風拂過菊花,嗯是的 就是那種感覺!
我們建立好了斷點,執行到斷點就自動停下來了,像這樣:
圖6

這些Debug的最基本操作技能是每一個入門的iOS開發者都要掌握的,應該當成一種本能,就像狗愛吃翔一樣(噢 對不起 博主不是歧視狗的意思,博主也養過狗,很二逼但是從不吃翔!真的據我所知它從來不吃翔的,這裡只是比喻只是比喻)。

 

全域性斷點(Global BreakPoint)

有時候在程式出錯的時候不能能準確定位到奔潰的那一行程式碼,而是直接跑到main迴圈或者Appdelegate裡面, 或者會給你這樣的提示:

EXEC_BAD_ACCESS:

是不是有種想哭的衝動?尼瑪~至少給我一些堆疊資訊也好呀~……這個時候你千萬不要砸滑鼠和鍵盤哦,一切都是主機在執行,你砸滑鼠和鍵盤有什麼用呢?應該是踢主機呀~~,現在有了全域性斷點,孃親再也不擔心你砸滑鼠了,你只需要這樣:
圖7

在Debug導航面板進行上圖的操作,你就建立了全域性斷點,這樣只要遇到錯誤,debug程式就會自動定位到棧底的資訊,也就是你最先出錯的程式碼的那一行,這樣你就可以快樂的debug拉~~

 

條件斷點(Condational Breakpoints)


從前有一個遊戲,叫做擼啊擼,有些玩家他們知道怎麼操作,會放技能會走路,但是他們不知道買裝備,玩了一局下來,鞋子小刀都沒有買。我為什麼講這個故事呢?因為很多小朋友學東西和玩遊戲一樣,看完前面的幾種除錯技能,就以為自己已經屌爆無敵了,其實他們不過是出門不帶裝備的玩家,如果只是使用了以上的除錯技能只能說是低玩,在高大的逼優雞面前根本就是會被瞬秒的那種,所以學會裝備自己才是王道!條件斷點,就是學會有的放矢!

我們來看一段程式碼
圖8

你是不是想問博主為何那麼風騷,竟然上了Swift了!!我此刻只想吟一首溼:別人笑我太淫蕩,我家住在黃鶴樓。
反正這個年代大家都是吃飽了撐著的,博主也是,所以就學學Swift咯。
我們如果在一個迴圈裡面使用了斷點,如果這個迴圈執行了100萬次,那你的斷點要執行那麼多次,你不覺得蛋蛋都涼了的憂傷麼?所以我們這麼做:
圖9

這樣只有遍歷到c==“H”的時候 斷點才會被觸發。

圖10

是不是很棒呢!
有些童鞋的鈦合金狗眼已經看到了編輯斷點那裡有一個Action的東西,那是什麼呢?
這個是非常強大的,可以在你斷點的位置,執行各種操作,比如執行指令碼命令,控制檯命令(可以制定除錯資訊自定義儲存)、列印資訊等,
博主最喜歡的就是這個Log message啦,簡單粗暴!根本就不需要print啊NSLog嘛,直接在斷點的Action列印就好了(其實這個是Xcode和偵錯程式結合的高能產物,下面再介紹)。具體可以這樣:
圖11

其實剛剛博主撒謊了,博主最喜歡的Action並不是Log Message,而是Sound,顧名思義嘛,斷點射在Bug上,這樣遇到斷點就會發出聲音,聽到我自己設定的聲音,我就知道是什麼Bug了,聽聲識Bug,呵呵,EXEC_BAD_ACCESS的錯誤我設定成了波多野老師的聲音,unrecognized selector send to instancd的錯誤我設定成了蒼老師的…… 不要問我係統怎麼沒有吉澤明步的聲音,我根本就不知道誰是吉澤明步。

當然還有更加強大的條件斷點就是這貨啦
圖12

新增之後在 Symbol 一欄輸入 viewDidLoad。
這樣一來,在程式中所有的 viewDidLoad 方法被呼叫時都會觸發斷點。
圖13


當然,我們也可以僅僅為特定的某個類的方法新增斷點。在 Symbol 一欄輸入 [ClassName viewDidLoad] (Objective-C) 或 ClassName.viewDidLoad (Swift) 即可。
比如:unrecognized selector sent to instance 0xaxxxx 這種錯誤,這個instance可以這樣快速定位
圖14

 

 

列印的藝術

儘管ARC已經讓記憶體管理變得簡單、省時和高效,但是在object的life-cycles中跟蹤一些重要事件依然十分重要。畢竟ARC並沒有完全排除記憶體洩露的可能性,或者試圖訪問一個被release的物件。為了這個目的,我們可以很藝術地偷窺物件正在做些什麼,想想就好有快感。

NSLog

小夥伴們第一節課學習ViewController的生命週期的時候,老師肯定很猥瑣的教了大家,在viewController的每個生命週期的方法中使用了NSLog來偷窺!沒錯,這樣其實就是最簡單爆炸的跟蹤生命週期的方法了,不過系統自己的NSLog真心有點羸弱,輸出的資訊太少,根本就不能滿足我們的慾望,這裡我教大家強化你的Log!!
可以用下面的這段巨集

//A better version of NSLog
#define NSLog(format, ...) do { \
fprintf(stderr, "<%s : %d> %s\n", \
[[[NSString stringWithUTF8String:__FILE__] lastPathComponent] UTF8String], \
__LINE__, __func__); \
(NSLog)((format), ##__VA_ARGS__); \
fprintf(stderr, "-------\n"); \
} while (0)

 

關於巨集的威力 大家可以亂入我的博文《 iOS中的預編譯指令的初步探究》
這樣打印出來的東西才像話嘛(其實NSLog的列印是非常低效的,甚至比print低100倍,感興趣自己翻翻蘋果手冊咯)。 
使用objc語言(強型別)並且用NSLog列印的時候,常常搞不清楚NSLog(@“%?”,xxx) xxx這種型別該是什麼什麼型別輸出,應該是%d呢還是%@亦或是%f???傻傻分不清楚~,所以玩轉NSLog你應該要知道以下這幾個全域性方法!
圖17

開啟殭屍物件(Enable NSZombie Objects)

Xcode可以把那些已經release掉得物件,變成“殭屍”,當我們訪問一個Zombie物件時,Xcode可以告訴我們正在訪問的物件是一個不應該存在的物件了。因為Xcode知道這個物件是什麼,所以可以讓我們知道這個物件在哪裡,以及這是什麼時候發生的。
所以Zombies是你的好基友!他可以讓你輸出的資訊更具體!!
具體這樣做:
圖15


自己再試試輸出Object的資訊咯,是不是很棒呢?
殭屍只能用在模擬器和OC語言哦~

 

進擊的碼農

如果說你已經把列印的藝術運用的風生水起了,並且斷點的使用可以信手拈來隨心所欲,那麼你已經在與逼優雞的對峙中,穩操大部分勝券了,你已經是一個孤高冷豔的程式設計師了,俯視一切低能的逼優雞了!但是!面對更強大的敵人——你那禿頂1000°近視牙齒夾著韭菜的有著十年對戰逼優雞的同事面前、以及笑裡藏刀眼睛有眼屎但是能用眼神殺死你的面試官…… 對於他們,你還是太弱,你的技能的磨練還太少!所以你必須要進擊!!比逼優雞還要強大的敵人出現了!我們需要更強大的武器。

Console(lldb 命令)

我們的目標是要武裝到鼻毛!console視窗大家知道就是哪個黑乎乎好多字會滾出來,尤其是被逼優雞幹到的時候,那麼同學們有沒有遇到這種console呢
圖16


我們家的編譯器歷史 敬請亂入 《iOS中的預編譯指令的初步探究》 ,沒錯我們現在正在使用著世界上最好的c、c++、oc、swift的編譯器——LLVM,lldb就是這個世界上最好的LLVM的偵錯程式!不要害羞,因為我們是最優秀的!所以肯定要用最好的!千萬別客氣喲,隨便用,就像自己家一樣啊,啊 哈哈 吃吃吃 別隻顧著吃飯,多夾菜……哎~博主好客的職業病又犯了~,什麼?你不知道在哪裡用lldb?
首先!你得先crash或者把程式斷下來!直到你看到圖16的(lldb)字樣出現,你就可以敲命令了~~
每次你想檢視變數,常量,你要重新寫NSLog去列印,然後重新編譯,去執行,重頭開始?太累了,有了lldb你只要這樣
圖18

是不是方便到爆炸?
當你有一個switch語句,你為了測試每一個case,你都要製造假條件去測試;有一個if…else…語句,你為了測試不同的情況,你要硬編碼寫了不同的情況,編譯好幾次為了測試每種情況……,我想你應該知道為什麼自己的頭髮那麼稀疏了。
以上的這些情況,只需一次編譯,使用lldb的thread命令,偽造返回值,欺騙暫存器,就可以隨心所欲的做完所有測試了。
是不是牛逼到爆炸?
lldb真的很強大,博主沒有騙你,這篇博文到此的所有除錯技巧lldb都可以實現,各種斷點,各種列印,呼叫python外掛,執行中斷,操作硬體底層,控制程式執行執行緒……lldb都可以做到!彷彿lldb就是另一個強大的世界!!!
是不是強大到爆炸?
其實如果你不想貪多嚼不爛的話,你只要精通這個除錯工具,基本前面的除錯技能你可以不用學了,在這裡博主也是不才,lldb的強大不是博主隨便說幾句就可以表達的出來的, 
更多地需要大家事必躬親,才能真正體會到那種美好,那種暢快無比的除錯體驗!
這裡博主無私地掏出任意門,這裡有很好的文章!可以讓你好好的回味,呵呵
《The LLDB Debugger》
《About LLDB and Xcode》
《LLDB除錯命令初探》
《與偵錯程式共舞 - LLDB 的華爾茲》

 

Profile(instruments)

 

圖19


這個東西怎麼翻譯呢?我們就叫檢查器吧!!也許已經學習了iOS開發大半年的你,從來都沒注意到或者使用這個工具,但是博主很負責任的告訴你現在市面上任何一款出色的APP都會使用instruments來讓程式碼更加健壯!難道instrument是春藥?怎麼會使程式碼健壯呢?
這個健壯不是那個健壯~哎~~ 我才18歲能不能清純一點呀

instrument裡面包含了很多工具,記憶體溢位分析,效能分析,各種分析…… 如果細說的話,這個真的可以為每個工具開一篇部落格,但是博主是一個懂得授人以魚不如授人以漁的道理的老司機!所以博主當然不會全部說一遍!我們就來領著大家看看專用debug的記憶體溢位分析工具的使用吧!
圖20


在使用leaks之前大家可以試試這個“Analyze”
圖21


analyze可以快速的發現你的程式碼中release的問題,以及繼承過程中的父類方法缺失等等問題!一般一個優秀的iOS開發工程師No Warning、Pass Analyze是最基本的操守!我知道你已經對於你自己的專案的上百個warning已經麻木了,但博主我負責人地告訴你,這樣不好!,因為有一首雲南民歌《老司機帶帶我》聽得博主神清氣爽!

堅守作為iOS開發者的貞操!跟著我高喊口號!

No Warning!Pass Analyze!

我們繼續回來使用leaks!如果analyze都通過了,那麼就可以使用leaks工具,發現千年老妖級別的側漏了!
圖22


如果提示某一個物件有側漏的風險,你還可以這樣彈出側邊的拓展細節
圖23


直接點選方法就可以直接進入程式碼部分了!!
是不是很簡單粗暴呢!當然還很多其他工具,不過叫做篇幅的東西總是限制人,誒 真蛋疼~真的還想多說點的 
想要更多瞭解instrument 大家可以看看這篇文章!
《How to Use Instruments in Xcode》

 

Xcode檢視除錯

有時候有些逼優雞隱藏的比較深,程式碼幾乎都翻了個遍,還是沒找到問題出在哪,博主可以理解那種風中凌亂,蛋碎一地的趕腳,因為無數個日夜博主就是深陷當中無法自拔,後來乾脆直接重新新建一個工程!還是不行!!我去,直到有一天博主早上起來,看到鏡子中自己帥氣的臉龐,我才突然頓悟,原來長得帥可以那樣快速的找到bug!最終鎖定是可愛又可恨的xib和storyboard出了問題!!某個constraint或者view的巢狀邏輯又或者團隊協作Git衝突等等問題,導致io -v什麼的錯誤,這種情況去檢查檢視檔案,可能xcode崩潰打不開那個xib或者storyboard,你直接使用文字工具開啟這個xml型別的標記檔案,你差點吐血,幾萬行的記錄狗眼都看瞎了……。

但是這個歷史要被終結!!因為我們強大的xcode的檢視除錯功能!!

以下內容,完全copy,如有不適,堅持看完!請叫我快樂的搬運工!
抄襲自《View Debugging in Xcode 6》
蘋果在Xcode 6中做了不少明顯的改善和優化,檢視除錯就是其中之一。通常,App使用者介面的行為不會符合開發者期望的那樣,比如或者不展示檢視,或者沒有正確地展示。本文講解如何使用Xcode的新的檢視除錯功能來簡化開發者對問題介面的確認和修復。

1.Demo 工程

開始之初先從github(https://github.com/tutsplus/ViewDebugging)上下載示例工程並開啟ViewDebugging.xcodeproj。該工程包含一個簡單的包含少數檢視控制器的可點選的應用程式、應用程式委託以及一個storyboard。該app是為iPhone而設計,但受益於iOS 8的自適應佈局,所以介面展示在任何裝置上都沒有問題。

您剛剛下載的應用程式示例工程是一個簡單的to-do list應用程式,包含可檢視其他資訊的簡單螢幕,比如該示例工程中的專案數,使用者頭像以及@***的推特操作。點選Xcode左上角的執行按鈕將展示在iOS模擬器中執行的應用程式。
圖24


很快會注意到使用者介面中存在問題-表檢視中沒有展示任何資料。在工程導航面板中開啟FirstViewController.swift並找到以下程式碼:

var mockNotesDataSource: [String] = [
    "Do some laundry", 
    "Finish homework", 
    "Walk the dog", 
    "Learn about view debugging"
]
{
didSet
{
self.tableView.reloadData()
}
}

 

可以看到mockNotesDataSource變數是表檢視的資料來源。使用Swift的屬性觀察者功能,在資料來源發生改變時,表檢視會自動重新載入。通過檢視以上程式碼片段,你會發現應該應用中應該有4個專案需要展示,但現在不展示資料就說明某些地方出現了差錯。

啟用檢視除錯

問題似乎與使用者介面有關。執行app過程中,按下底部的Debug View Hierarchy 按鈕,或者從選單中選擇Debug > View Debugging > Capture View Hierarchy 來啟動檢視除錯。

圖25


啟動檢視除錯後,Xcode會對應用程式的檢視層次拍一個快照並展示三維原型檢視來探究使用者介面的層級。該三維檢視除了展示app的檢視層次外,還展示每個檢視的位置、順序和檢視尺寸,以及檢視間的互動方式。

示例工程在Xcode中的三維檢視展示正常,但表檢視單元格似乎有點太寬了。
圖26


暫停應用程式除錯並在左側選中Main.Storyboard來修復問題。點選表檢視並選中Editor > Resolve Auto Layout Issues > Reset to Suggested Constraints.
圖27


編譯並再次執行應用程式以確定使用者介面展示正常。點選Debug View Hierarchy按鈕更進一步瞭解檢視除錯的功能。

檢視除錯功能

點選並拖拽三維渲染圖的任意一邊,可旋轉或者傾斜使用者介面,向左或者向右傾斜可選中某個表檢視。

選中後,Xcode會高亮該檢視,並在會在右邊展示Object 和Size檢查器。檢視在跳轉欄頂部並確認UITableView是右邊最後一個專案。
圖28

Object 和 Size檢查器包括大量有用的資訊。過去開發者需要依賴日誌語句或者斷點來檢查檢視的配置。

開啟右邊的Size inspector(規格檢查器),下方是Auto Layout,可以看到檢視上已經應用了正確的約束。在Object inspector中,我們可以檢查所選檢視的屬性。
圖29

在Xcode的除錯區有9個檢視除錯過程中要用到的按鈕和滑塊兒。
圖30


從左到右控制元件排序:

調整檢視間距:調整不同檢視間的間距。

展示被剪下的內容:當前展示檢視中被剪下的部分。

展示約束:展示選中檢視的約束。

重置檢視區域:將3D渲染透檢視恢復至預設狀態。

調整檢視模式:選擇性地展示3D渲染透檢視,比如僅展示內容,僅展示框架以及同時展示內容和框架。

縮小:縮小3D渲染透檢視

恢復:將3D渲染透檢視恢復至預設尺寸。

放大:放大3D渲染透檢視

調整可視檢視範圍:隱藏檢視或展示檢視,一步步解析3D渲染檢視,向左或者向右滑動滑塊兒有相反的效果。

建議花一點時間上手操作下這些空間,並理解各自的用處。

檢視層排序

再次編譯和執行應用程式,並點選使用者介面底部的"More"標籤。第一眼看去介面看起來還OK,但是它沒有按照開發者的定義準確執行,圖片上的模糊效果沒有展示出來。我們可以通過除錯檢視層次來更好地確定問題所在。

向左或者向右拖拽檢視來檢視具體情況,接著將view spacing slider向右拖動。
圖31


這樣一來,不同檢視間的間距變大了,層次也更加清晰,我們看到在圖片"下方"還隱藏著另一個檢視,選中隱藏的檢視,它就是"丟失"的視覺效果檢視。
圖32


開啟Main.storyboard 並選中Second View Controller Scene。在左側的文件概覽面板中,展開Second View Controller的檢視物件以檢視子檢視的排序。

Xcode在文件概覽中按照遞升順序堆疊檢視,換句話說,列表頂層的檢視是檢視層次的基礎。

修復問題很簡單。執行時,Blur Effect View隱藏在Sky Image之下,因為它是檢視層次的第一個檢視。在文件概覽中點選並拖拽 Blur Effect View,結果會如下圖展示一樣:
圖33


再次執行應用程式就能看到模糊效果了。應用程式的使用者介面看起來符合設計的初衷。我們還可以檢視iOS模擬器的其他除錯功能,看看還完善了其他什麼地方或功能。

5.iOS模擬器除錯功能

編譯並執行應用程式,選中模擬器,從 Debug選單中選擇Color Blended Layers選項。
圖34


然後會看到app的使用者介面被紅色和綠色覆蓋,顯示了哪些圖層可以被疊加覆蓋,以及哪些圖層是透明的。混合層屬於計算密集型檢視,所以推薦儘可能地使用不透明的圖層。
圖35


蘋果在其文件(iOS Simulator User Guide)中對此進行了註明,並在表檢視處理上使用了不透明圖層。滾動檢視時會有些表現不大好的地方,一個重要的原因就是使用了混合圖層,而如果內容背景是不透明層,那麼頁面滾動效果就會非常流暢和平穩。

對於這款應用程式來說,假使使用者有數百個專案要展示,可能會出現滾動效能不一致的情況。表檢視單元格當前使用的是混合層。由於檢視控制器的檢視背景是白色,所以不管表檢視單元格使用的是混合層或者不透明層,終端使用者不會覺察到有什麼不一樣。

開啟Main.storyboard並選中To Do list Scene中的表檢視單元格屬性。在屬性檢查器(Attributes Inspector)中,向下滾動Drawing分割槽並勾選Opaque。
圖36


在啟用Color Blended Layers的狀態下編譯並執行應用程式。由於表檢視單元格現在使用了不透明層,所以會用綠色覆蓋,以指示它們是不透明的。

除了標記圖層外,還有其他一些有用的功能可幫開發者在iOS模擬器中除錯應用。以下是其中一些比較有用的:

Toggle Slow Animations in Frontmost App: 選中模擬器,開啟Debug選單選中Toggle Slow Animations in Frontmost App,該功能可以降低app中動畫的執行速度,適合除錯包含複雜動畫的應用程式。也可是使用快捷鍵Command-T來操作。
Color Copied Images:該選項可以給繪製時被Core Animation複製的圖片新增藍綠色疊加層。
Color Misaligned Images:如果圖片邊界沒有與目標畫素完美對齊,該功能可為圖片疊加上一層品紅色。如果圖片使用確定的比例大小繪製,那麼該功能會為圖片新增一層黃色疊加。
Color Off Screen Rendered:.該選項為離屏渲染內容新增一個黃色的疊加層。
很多開發者會忽略接入電話時應用狀態列的設計問題,你可以通過觸發通話中狀態列來簡單測試。在iOS模擬器中,從Hardware選單中選中Toggle In-Call Status Bar。

想檢視app如何響應事件,可按下Command-T來啟用slow animations,並按下Command-Y來展示電話接入時的狀態列。倘若你的應用程式使用了導航欄,那麼作業系統會為你兼顧到這一塊兒。
圖37


除了給檢視著色外,還要記住iOS模擬器也可以除錯Core Location問題。你可以在特定經緯度模擬裝置,

如果你的應用程式使用iCloud來管理資料,你也可以手動觸發同步事件。

本文中使用的demo app非常簡單,使用文中提到的技術可以幫你在未來節省不少時間。檢視除錯可以幫你修正很多使用者介面中出現的問題。

除了Xcode和InterfaceBuilder之外,使用iOS模擬器的除錯功能可以提升應用效能和識別開發過程中的瓶頸。蘋果的人機互動指南(中文版 英文版)強調了積極響應對app的重要性,能讓使用者覺得應用易於使用和操作。蘋果對InterfaceBuilder的提升讓檢視除錯變得前所未有的簡單。

結語

這篇文章博主花了3個禮拜,斷斷續續才寫完的,當中錯漏應該非常多,但是無論如何鄙人覺得應該算是配的上豪華套餐的稱號了,當中iOS開發的基本、常用以及高階的除錯技能都涉及了,但是仍然有很多其他的奇門巧技沒有介紹到,主要是可惡的“篇幅”限制住了博主廣博的愛,但是無論如何,這篇文章大家暫且可以當做是一個除錯技術的目錄,因為博主在這裡寫的講的很粗淺,你不應該只滿足於這篇文章,你如果想要改變世界的話,你應該藉著博主的這篇目錄式文章深入地學習與研究!