xcode 中的調試

可以通過對斷點的編輯,形成不同的調試結果。

設置帶判斷條件的斷點。

可以設置控制臺輸出內容的斷點(也可以設置語音)


可以直接設置返回值的斷點(通過lldb調試器,斷點后邊的值就不執行了)

添加全局斷點

給全局中的函數添加斷點

添加之后在 Symbol 一欄輸入 viewDidLoad。


這樣一來,在程序中所有的 viewDidLoad 方法被調用時都會觸發斷點。

當然,我們也可以僅僅為特定的某個類的方法添加斷點。在 Symbol 一欄輸入 [ClassName viewDidLoad] (Objective-C) 或 ClassName.viewDidLoad (Swift) 即可。


比如:unrecognized selector sent to instance 0xaxxxx 這種錯誤,這個instance可以這樣快速定位


打印的藝術

盡管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)

在控制通過lldb調試器做調試工作。有開源庫Chisel

1.print (縮寫為p)輸出當前斷點所在模塊內的值。結果中有個$0。實際上你可以使用它來指向這個結果。試試print $0 + 7,你會看到106。任何以美元符開頭的東西都是存在于 LLDB 的命名空間的,它們是為了幫助你進行調試而存在的。

p objects:打印對象縮寫為po

2.expression 如果想改變一個值怎么辦?你或許會猜modify。其實這時候我們要用到的是expression這個方便的命令。

p count = 18。如果我們運行這條命令,然后打印count的內容。我們將看到它的結果與expression count = 18一樣。

和expression不同的是,print命令不需要參數。比如e -h +17中,你很難區分到底是以-h為標識,僅僅執行+17呢,還是要計算17和h的差值。連字符號確實很讓人困惑,你或許得不到自己想要的結果。

幸運的是,解決方案很簡單。用--來表征標識的結束,以及輸入的開始。如果想要-h作為標識,就用e -h -- +17,如果想計算它們的差值,就使用e -- -h +17。因為一般來說不使用標識的情況比較多,所以e --就有了一個簡寫的方式,那就是print。

3.thread return x
斷點所在的函數,以某個值(x),直接做保存。

4.更新UI

有了上面的輸出,我們可以獲取這個 view:

(lldb) eid$myView = (id)0x7f82b1d01fd0

然后在調試器中改變它的背景色:

(lldb) e (void)[$myView setBackgroundColor:[UIColorblueColor]]

但是只有程序繼續運行之后才會看到界面的變化。因為改變的內容必須被發送到渲染服務中,然后顯示才會被更新。

渲染服務實際上是一個另外的進程 (被稱作backboardd)。這就是說即使我們正在調試的內容所在的進程被打斷了,backboardd也還是繼續運行著的。

這意味著你可以運行下面的命令,而不用繼續運行程序:

(lldb) e (void)[CATransactionflush]

5.Push 一個 View Controller

想象一個以UINavigationController為 root ViewController 的應用。你可以通過下面的命令,輕松地獲取它:

(lldb) eid$nvc = [[[UIApplicationsharedApplication] keyWindow] rootViewController]

然后 push 一個 child view controller:

(lldb) eid$vc = [UIViewControllernew](lldb) e (void)[[$vc view] setBackgroundColor:[UIColoryellowColor]](lldb) e (void)[$vc setTitle:@"Yay!"](lldb) e (void)[$nvc pushViewContoller:$vc animated:YES]

最后運行下面的命令:

(lldb) caflush// e (void)[CATransaction flush]

查找按鈕的 target

想象你在調試器中有一個$myButton的變量,可以是創建出來的,也可以是從 UI 上抓取出來的,或者是你停止在斷點時的一個局部變量。你想知道,按鈕按下的時候誰會接收到按鈕發出的 action。非常簡單:

(lldb) po [$myButtonallTargets]{(? ? )}(lldb) po [$myButtonactionsForTarget:(id)0x7fb58bd2e240forControlEvent:0]<__NSArrayM 0x7fb58bd2aa40>(_handleTap:)

現在你或許想在它發生的時候加一個斷點。在-[MagicEventListener _handleTap:]設置一個符號斷點就可以了,在 Xcode 和 LLDB 中都可以,然后你就可以點擊按鈕并停在你所希望的地方了。

觀察實例變量的變化

假設你有一個UIView,不知道為什么它的_layer實例變量被重寫了 (糟糕)。因為有可能并不涉及到方法,我們不能使用符號斷點。相反的,我們想監視什么時候這個地址被寫入。

首先,我們需要找到_layer這個變量在對象上的相對位置:

(lldb) p (ptrdiff_t)ivar_getOffset((struct Ivar *)class_getInstanceVariable([MyViewclass], "_layer"))(ptrdiff_t) $0 =8

現在我們知道($myView + 8)是被寫入的內存地址:

(lldb) watchpointsetexpression -- (int *)$myView+ 8Watchpoint created: Watchpoint 3: addr = 0x7fa554231340 size = 8 state = enabledtype= w? ? new value: 0x0000000000000000

這被以wivar $myView _layer加入到Chisel中。

非重寫方法的符號斷點

假設你想知道-[MyViewController viewDidAppear:]什么時候被調用。如果這個方法并沒有在MyViewController中實現,而是在其父類中實現的,該怎么辦呢?試著設置一個斷點,會出現以下結果:

(lldb) b -[MyViewController viewDidAppear:]

Breakpoint 1: no locations (pending).

WARNING:? Unable to resolve breakpoint to any actual locations.

因為 LLDB 會查找一個符號,但是實際在這個類上卻找不到,所以斷點也永遠不會觸發。你需要做的是為斷點設置一個條件[self isKindOfClass:[MyViewController class]],然后把斷點放在UIViewController上。正常情況下這樣設置一個條件可以正常工作。但是這里不會,因為我們沒有父類的實現。

viewDidAppear:是蘋果實現的方法,因此沒有它的符號;在方法內沒有self。如果想在符號斷點上使用self,你必須知道它在哪里 (它可能在寄存器上,也可能在棧上;在 x86 上,你可以在$esp+4找到它)。但是這是很痛苦的,因為現在你必須至少知道四種體系結構 (x86,x86-64,armv7,armv64)。想象你需要花多少時間去學習命令集以及它們每一個的調用約定,然后正確的寫一個在你的超類上設置斷點并且條件正確的命令。幸運的是,這個在Chisel被解決了。這被成為bmessage:

(lldb) bmessage -[MyViewController viewDidAppear:]Setting a breakpoint at -[UIViewControllerviewDidAppear:] with condition (void*)object_getClass((id)$rdi) ==0x000000010e2f4d28Breakpoint1: where =UIKit`-[UIViewControllerviewDidAppear:], address =0x000000010e11533c

LLDB 和 Python

LLDB 有內建的,完整的Python支持。在LLDB中輸入script,會打開一個 Python REPL。你也可以輸入一行 python 語句作為script 命令的參數,這可以運行 python 語句而不進入REPL:

(lldb) scriptimportos(lldb) script os.system("open http://www.objc.io/")

這樣就允許你創造各種酷的命令。把下面的語句放到文件~/myCommands.py中:

defcaflushCommand(debugger, command, result, internal_dict):? debugger.HandleCommand("e (void)[CATransaction flush]")

然后再 LLDB 中運行:

command scriptimport~/myCommands.py

或者把這行命令放在/.lldbinit里,這樣每次進入 LLDB 時都會自動運行。Chisel其實就是一個 Python 腳本的集合,這些腳本拼接 (命令) 字符串 ,然后讓 LLDB 執行

啟動視圖測試:


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

圖26

暫停應用程序調試并在左側選中Main.Storyboard來修復問題。點擊表視圖并選中Editor > Resolve Auto Layout Issues > Reset to Suggested Constraints.

圖27

編譯并再次運行應用程序以確定用戶界面展示正常。點擊Debug View Hierarchy按鈕更進一步了解視圖調試的功能。

視圖調試功能

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

選中后,Xcode會高亮該視圖,并在會在右邊展示Object 和Size檢查器。查看在跳轉欄頂部并確認UITableView是右邊最后一個項目。

圖28

打開右邊的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模擬器的其他調試功能,看看還完善了其他什么地方或功能。

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問題。你可以在特定經緯度模擬設備,

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容