新版本Xcode 6的視圖調試詳解

1429754949114999
開發者會常常遇到視圖或者Auto Layout約束中存在bug的狀況,而且這種bug很難經過代碼發現,因此開發者頗有必要熟知如何進行簡單高效的視圖調試,而Xcode 6的發佈使得視圖調試變得史無前例的簡單。html

開發者不用將frames打印到控制檯,而後在腦海中可視化視圖的佈局,如今你能夠在Xcode中查看整個視圖層次。ios

本教程會帶你熟悉全部能夠操做的不一樣選項。你作好寫代碼的準備了嗎?這個問題有點使人煩心,由於你根本就不想寫代碼。你能夠在Xcode 6中檢查開源庫的視圖層次,瞭解它的編寫方法---最重要的是不用看任何代碼。git

開始github

本教程使用Jesse Squires 編寫的JSQMessagesViewController庫,庫的UI看起來很是熟悉,相似Messages app。canvas

先在 GitHub project page下載源碼並解壓。xcode

注意: 該庫使用了CocoaPods來管理和其餘庫之間的依賴關係,不熟悉的話能夠先看看CocoaPods tutorialapp

接着在終端找到解壓項目,運行 pod install 安裝所需依賴關係。打開JSQMessages.xcworkspace並編譯,而後在iPhone5s模擬器中運行應用程序。  (可以使用任意尺寸的模擬器,本教程中使用的是4英寸的模擬器,你能夠選擇4英寸模擬器以便於快速瞭解教程內容)編輯器

注意: Live View Debugging僅支持在iOS 8上運行應用程序,不支持iOS 7,即使你用的是Xcode 6。ide

點擊項目中的 Push via storyboard選項 進入與Steve Jobs 和Tim Cook消息發送界面線程,這就是你將要查看的視圖。工具

1429694642278968

Even Steve Wozniak joins the fun!

回到Xcode並點擊調試欄中的Debug View Hierarchy按鈕 ,或者經過Debug\View Debugging\Capture View Hierarchy操做,效果是同樣的。

1429694748777381

Xcode會打斷app的運行並進行調試,該操做和你使用調試欄上的的"pause"按鈕暫停app運行同樣。此外,Xcode會展現canvas(譯者注:如下簡稱"畫布")而不是代碼編輯器。Xcode在canvas上繪製了app主窗口的整個視圖層次,包括指示每一個視圖邊界的細線(稱之爲線框圖)。

1429694762683960

若是往視圖層次上添加一個子視圖,也就是在當前的視圖堆棧上添加layer。因爲大部分views不會疊加,因此運行app時,全部的views看起來像是大layer的一部分,下圖很是接近這種描述,不過帶着一些額外的線。

如今你所看到的是一個可視化的視圖堆棧。在canvas中點擊並拖動,會看到視圖層次的3D模型。

1429695424858773

你能夠從上、下、左、右多個角度查看視圖層次。

1429695450541161

注意:在嘗試的過程當中,canvas可能不會像教程中展現的這樣。爲確保你是在同一個頁面,請按下cmd + 6 調出Debug navigator。

在面板底部左側有兩個按鈕。以下圖所示,取消對這兩個按鈕的選定,不然會隱藏一些視圖。

1429695475788612

探索視圖層次(Exploring the View Hierarchy)

最天然最經常使用的方式是從左邊開始探究3D模型,稍後教程爲解釋爲何要這麼作。向左拉動視圖層次,以下圖所示:

1429695501435834

若是你想可視化app的構建,那麼從多個角度查看視圖層次就很是有用了。不過,在堆棧的底部(左邊)有不少空視圖,它們是什麼呢?

點擊最左邊的視圖(也就是最後邊的視圖),Xcode會對其進行高亮。畫布上方的Jump Bar(跳轉欄)更新展現一個UIWindow做爲最新項目--最新項目一般指出了當前選中的項目以及其class類型。

1429695927280018

因爲該app只使用一個窗口,因此可假定位於跳轉欄前邊的UIWindow 是app的主要窗口,也就是AppDelegate的 window 屬性。

不過,彷佛檢查這個圖層並無多大意義。那下一個視圖呢?在畫布中,點擊窗口最右邊的視圖(也就是最上邊的視圖),再看看跳轉欄(Jump Bar)看看有什麼不同的。UILayoutContainerView,甚至不是一個公開類。

1429695955379793

這時候,視圖層次看起來是這樣的:

1.UINavigationTransitionView:導航控制器在這裏發生轉場行爲的容器視圖。

2.UIViewControllerWrapperView: 包含view controller 的view屬性的封裝視圖。

3.UIView: view controller的最上層視圖 (與view controller的view 屬性一致)

4.JSQMessagesCollectionView: 工程使用collection view來展現全部消息。

Focusing on Views of Interest(關注與調試相關的視圖)

在調試該特定視圖層次時,頭四個視圖(從窗口開始)其實是視覺"噪音",它們並沒有多大意義,會讓你分心,若是能過濾掉這些"噪音"視圖就最好不過了。

你固然能夠這麼作!在畫布的右下角有一個雙滑塊兒滑桿,左右滑動滑塊可幫你暫時隱藏一些視圖,默認狀況下,滑塊在滑桿的左右兩端。

1429696090977217

將滑塊左端滑塊向右滑動一點,畫布中app的線框圖會一層層消失。將滑塊兒拖得更遠一點,UINavigationTransitionView也消失不見了。

根據須要將左端滑塊兒儘量拖得遠一些,從而隱藏JSQMessagesCollectionView的父視圖。你的畫布看起來應該和下邊相似:

1429696112701944

在右側,你會發現導航欄彷佛有點讓人分心,可是它的的確確位於collection view的最上層,不方便查看下層佈局。幸運的是你能夠隱藏它。

因爲你主要關於屏幕上較小的一個區域,而且導航欄上還有不少比導航欄更小的元素。這時候放大導航欄可讓你更清楚地看到界面是如何佈局的。

使用縮放控件按鈕,它是一組三個的按鈕,居中展現在畫布中。

1429696193156791

這一組按鈕有放大"+"、縮小"-"以及將視圖重置到正常的水平的"="三種選擇,

1429696200626356

注意:若是你使用的是觸控板,兩指捏合和縮放也能縮小和放大視圖。若是你一次性縮放過多,那麼屏幕上的內容就不能徹底展現,這時候使用觸控板仍是比較有用的。固然你也可使用鼠標滑輪進行縮放。

雖然經過縮放toolbar得到額外的細節很是不錯,但這些視圖仍牢牢地疊加在一塊兒,要分清誰是誰並不容易。

想要解決這個問題,可使用畫布左下角的spacing slider,向右拖動圓形滑塊兒越遠,不一樣同視圖之間的間距。視圖間的間距會隨着滑塊兒拖動的距離增長而變大。

1429696407510383

在該案例中,儘量地向右移動滑桿兒,以免工具欄中視圖疊加。你能夠試試在畫布上拖放視圖以達到理想的效果。

1429696443449502

畫布右下角隱藏視圖的滑桿,將右端滑塊兒移至左端,直到剩下UINavigationBar。選擇最上邊的圖層,你可使用Jump Bar來辨認每一個視圖的類。首先你會看到導航項目消失了,接着是包含它們的按鈕,而後是一些私有視圖,最後是導航欄。

1429696479979339

啊?沒有導航欄了!

注意:旋轉畫布查看3D視圖層次,若是最頂層視圖位於左側,那麼滑桿兒的左側滑塊兒依舊從堆棧底部移除視圖,如今是在右側。一樣,無論頂層視圖在左側仍是右側,右側滑塊兒都從堆棧的頂部開始移除。

將滑塊兒從左側移至右側,視圖從右向左逐漸消失(反之亦然),這是有違直覺的,這也是讓頂層視圖位居右側,這種查看3D模型的方式纔是最天然的方式,就是咱們在教程最初提到的那一點。

不幸的是,隱藏導航欄(包含_UIBackdropView根視圖)視圖也會讓屏幕底部toolbar裏的內容消失。調整縮放度或向下移動畫布才能看到發生的變化。

因爲toolbar項目是屏幕上重要的一部分,你須要查看這些內容,因此僅僅隱藏視圖直到(但不包括)剩下_UIBackdropView,導航欄堆棧看起來像是下邊這種:

1429696520590046

More View Options(更多視圖選項)

如今已經隱藏了不相關的視圖,咱們接着要從正面再看這個屏幕。你能夠將3D模型拖回原位,不過有時候很難剛恰好,還好咱們有其餘辦法。

在3D模型的下方---縮放按鈕的左側有一組四個按鈕,從左向右數第三個按鈕是ResetViewing Area按鈕,它能夠取消旋轉並從正面展現視圖層次,像在模擬器或者設備上同樣。

1429696564846874

畫布看起來應該和下邊的同樣:

1429696585426551

你可能注意到你在調試器中所見到的,並不全是app實際運行時的樣子。

首先,單個視圖周圍易燃有線框圖包圍,它們可讓你查看透視圖或者沒有任何內容的視圖,不過若是你不須要細節信息,線框圖就會讓事情變得雜亂。

你可使用View Mode按鈕進行選擇-在Reset Viewing Area按鈕的右側。點擊視圖模式按鈕,你能夠選擇只查看線框圖、只查看內容或者同時查看二者。

1429696609833167

若是你主要是對位置感興趣,而且不大關心視圖看起來什麼樣子,那麼線框圖是很是有用的。當你想要調試視圖的外觀時,僅展現視圖內容就很是有用了。

想要減小線框圖引發的雜亂(尤爲是靠近導航欄和toolbar的地方),可將查看模式更改成Contents ,以移除全部線框圖,僅留下app的核心部分。

1429696763494631

接下來,是從當前視圖中忽略的幾點。

當你運行app時,你將會看到文本氣泡上的標籤,指示信息發送者名稱或者信息的時間戳,以及最後一個氣泡中Golden Gate Bridge的圖片。可是調試器並不會展現這些標籤和圖片。想要解決這個問題,可查看畫布上中間一組按鈕的第一個,可展現或者隱藏省略掉的視圖。這些視圖的clipsToBounds屬性設置爲了YES。

1429696790715287

這是標籤相關的,大概因爲較長的名字和日期不該當延伸到標籤的界限以外。這一點一樣應用於圖片,圖片使用圓角半徑並剪切以生成圓角圖片。點擊該按鈕,你會注意到這些視圖將再也不出如今Xcode中。

1429696798208689

注意:你可能注意到可視項目周圍仍有線框圖,若是是這種狀況,使用你先前使用的View Mode按鈕

打開和關閉線框圖,問題便可解決。

你已經都瞭解了:在Xcode中近乎完美地複製了視圖層次。

1429696827983006

So easy!

Inspecting Views(查看視圖)

已經瞭解了最重要的部分,如今看看這些不一樣視圖的佈局。

你已經知道了collection view如何讓這些視圖彙集在一塊兒,可是若是能看到這些不一樣元素的總體結構就更好了。固然能夠啦!

按下cmd + 6 調出Debug navigator,和其餘調試會話同樣,Debug navigator提供了當前會話的文本信息。對於視圖調試來講,這意味着Xcode提供了全部窗口中視圖的視圖樹。展開Debug navigator的視圖樹後是這個樣子的:

1429696879986684

注意:在Debug navigator的底部,你會看到一個選項能夠控制在視圖樹中展現哪一種類型的項目。蘋果的文檔表示左邊的按鈕將系統視圖實現的私有元素過濾出來,不過這個按鈕在Xcode 6.2中彷佛不起做用。

右邊按鈕可隱藏那些將其 hidden 屬性設置爲YES的視圖,而且搜索欄僅展現匹配搜索條件的視圖和約束。

出於本教程的目的,取消對這兩個按鈕的選擇,而且不使用任何搜索過濾。

這是個不錯的而開始。展開最後一個JSQMessagesCollectionViewCellOutgoing,它只有一個子視圖UIView。若是你之前使用過collection view,那你應該知道這個是講得通的,由於任何UICollectionViewCell都有一個包含cell內容的contentView 屬性。

點擊但不要展開-將鼠標放在Debug navigator的UIView 上,你會看到Xcode已經在畫布上對其高亮,這樣你就準確知道它在屏幕的什麼地方。

1429696913610493

想要真正瞭解iOS如何放置該cell,可以使用cmd + option + 4打開Size Inspector,該導航器的頂部形象化了視圖的邊界、位置以及錨點。

1429696929184303

不過,真正有趣的部分是應用於該視圖的Auto Layout約束列表。你能夠馬上將cell的內容視圖的寬和高分別設定爲312 point和170 point,並將其居中。封閉的cell一樣是312*170 point,因此內容視圖佔據了整個cell。下邊用灰色顯示的約束表示它們是指出視圖和其子視圖之間關係的約束。

想了解一個特定約束的更多細節,首先要展開視圖樹中的視圖,而後展開Constraints項目。你將會看到和Size navigator中同樣的約束列表。

1429696943739947

點擊第一個約束(self.midX的約束),並經過cmd + option + 3切換至Object inspector。你會看到一個約束概覽。編輯約束時,這一點很是相似於Interface Builder。

1429696960163844

除了尺寸和約束信息,你還會看到Object Inspector中特定視圖的其餘信息。回到Debug navigator,展開視圖樹中的UIView ,你會到它有3個JSQMessageLabel和兩個UIView。選中第一個JSQMessageLabel(帶有時間戳的那個),並打開Object Inspector。

1429755120518521

第一個部分展現了對象的類名稱和內存地址,第二部分展現了對象的多個公有屬性的值。

從圖中看出,標籤文本的顏色是無alpha 的0.67灰,字體大小是12pt。

針對它們如何被可視化,其餘類也有一些有用的信息。回到Debug navigator,展開cell的根UIView 中的第二個UIView,你會看到一個UIImageView。

1429697008947605

從視圖樹中選擇image view,並查看Object inspector。

1429755284547087

你正查看的是展現用戶頭像的視圖-在該例子中是做者的首字母JSQ,你會看到常規圖片、便利的貼有標籤的圖片、較暗的圖片以及被標記的高亮,這些將在用戶點擊cell時展現。

在cell的根視圖中,JSQMessageLabel的其餘兩個實例當前尚未文本,但它們被用於即將進來的消息發送者的名字和消息發送失敗時的錯誤信息。

怎麼樣,在Xcode中調試視圖很是簡單吧,繼續運行該app,點擊Debug bar上的"Continue"按鈕,或者執行Debug\Continue,就像你在常規調試中那樣。

Live Modifications(實時調整)

如今你已經瞭解了使用Xcode 6進行視圖調試的基礎支持,接下來將你所學應用到一個小小的實驗中:只使用調試器,確保你在本教程中使用的collection view的垂直滾動指示器爲red。

你能夠從如下兩點開始:

1.因爲視圖調試和其餘調試部分很是像,你能夠在終端使用expr 和其餘命令,可是須要從新運行項目才能看出所作的變化。更多關於這些命令的信息,請查看debugging apps in Xcode教程

2.因爲Objective-C中的指針僅僅是內存地址,因此當你發送對象時,你僅僅發送了一個內存地址。這一樣適合於調試器,因此相似po 0x123456abcdef這樣的命令會打印出內存地址中的對象描述。

多作幾回嘗試,若是出現問題,可嘗試如下解決方案:

首先要確保將視圖模式設置爲"Contents"

1429755357905850

在Debug navigator中,展開collection view的視圖樹,以便清楚知道視圖的子視圖。

1429755371207520

collection view的最後視圖是兩個UIImageView實例,是水平方向和垂直方向上的滾動指示器。點擊第二個,你會看到水平方向上的指示器在畫布中被高亮。

1429755399282396

從Object inspector中複製圖片視圖的內存地址。

1429755409686888

在這個例子中,滾動指示器的內存地址是0x7fde6c484640。須要作的是給該地址中的對象發送一個setBackgroundColor:信息可將滾動指示器着色。可以使用如下代碼:

繼續運行該應用程序,在滾動collection view時,滾動指示器變成了紅色。

祝賀你,你已經瞭解了使用Xcode 6進行視圖調試的基本內容。

Old School Debugging(保守調試)

實時調試讓使用Xcode 6進行視圖調試變得很是簡單,但並不意味你以前經常使用的調試方法已經沒有用武之地了。事實上,除了視圖調試外,iOS 8引入了一個很是受歡迎的技巧: _printHierarchy.

注意:你已經瞭解了Xcode 6視圖調試的基本內容,因此若是你不喜歡能夠直接跳過這個章節。不過若是你很是癡迷一些便捷的舊的技術,那不要錯過這個。

打印View Controller Hierarchy

_printHierarchy是 UIViewController 的一個私有方法,你能夠用它將view controller 層次打印到控制檯。編譯並運行,選中Push via storyboard,而後點擊Debug bar上的"pause"按鈕。

在終端打出如下內容並從新運行:

獲得相似下面的內容:
1429755554532887

這告訴你UINavigationController的第一個視圖控制器是一個TableViewController,你能夠選擇如何推出控制器。第二個view controller是DemoMessagesViewController,或者你已經調試過的view controller。

這個例子彷佛不怎麼使人興奮,但若是你的導航控制器中有幾個view controller,或者彈出視圖中有tab bar控制器,那麼想要弄清楚這些view controller如何工做, 這個功能就很是有用了。

Printing the View Hierarchy(打印視圖層次)

若是你更喜歡文本化的視圖層次,那你可使用UIView舊的私有recursiveDescription。這個方法打印出來的視圖層次很是相似於上邊描述的view controller層次。

打開Views\JSQMessagesCollectionViewCellOutgoing.m 並在awakeFromNib中添加一個斷點。

1429755597643584

編譯並運行,而後選擇Push via Storyboard。調試器有問題了,由於加載了JSQMessagesCollectionViewCellOutgoing。如今在控制檯輸入如下代碼:

這將打印出 JSQMessagesCollectionViewCellOutgoing的contentView層次, 看起來像這樣:

1429755624847198

這是基本的,但能夠幫你調試iOS 8以前的視圖層次。

Using debugQuickLookObject(使用debugQuickLookObject)

最後,Xcode5.1引入了Debug Quick Look功能。若是你已經作好了調試的準備,但不大想知道某段代碼如何實現對象的特定外觀,那麼這時候這個功能就很是有用了。

你的自定義類能夠實現debugQuickLookObject方法,並返回任何由Xcode展現的內容。此外,若是你已經正進行調試,而且已經有了想要查看的對象,你可使用快速查看功能,而且Xcode會以可視化形式表示對象。

好比,NSURL對 debugQuickLookObject的實現返回了一個帶有URL 的UIWebView,你能夠真實看到URL背後的東西。

關於使用Quick Look調試的更多信息,請查看相關文檔

下一步

以上是關於實時調試的內容,它是一個能夠幫助節省大量時間的工具,很是好用。

相關文章
相關標籤/搜索