デバッグのためにView階層を把握する

※この記事はApple公式の「[Debugging View Hierarchies](https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/debugging_with_xcode/chapters/special_debugging_workflows.html)」をベースにして「[よくわかるAuto Layout iOSレスポンシブデザインをマスター](https://www.amazon.co.jp/よくわかるAuto-Layout-iOSレスポンシブデザインをマスター-川邉-雄介/dp/4865940324)」を参考にしつつ書いています。ちなみにこの記事執筆時に私が使っているXcodeのバージョンは8.1です。

# ビューデバッガーの使いどころ

あるviewがどこにくっついているのかわからない時に使うことが多いと思います。「なんでこのviewは隠れてしまっているんだろう」「removeFromSuperView()してこのviewも消えるはずなのになんで残ってるんだろう」などの疑問を感じた時に役に立ちます。

# ビューデバッガーの表示

一番簡単なのはアプリ実行中にXcode下部にあるデバッグバーのDebug View Hierarchyボタンをクリックすることです。
![スクリーンショット 2016-12-04 12.45.16.png](https://qiita-image-store.s3.amazonaws.com/0/100736/da020742-0468-a03a-93ec-6c2c4e0012f3.png)

もしくはXcodeのメニューバーからDebug > View Debugging > Capture View Hierarchyを選択することでも表示させることができます。

ビューデバッガーを表示すると以下の状態になり、現在のビュー階層を3Dで見ることができるようになります（プロジェクト名が適切でなくてごめんなさい）。
![スクリーンショット 2016-12-04 13.32.53.png](https://qiita-image-store.s3.amazonaws.com/0/100736/86fa0cb5-7324-1ea4-9d10-775be0c6d50d.png)

左ペインではView Hierarchyが、中央では3Dでビュー階層が、右ペインでは現在選択しているviewの様々なプロパティが見見られるようになっています。中央エリアはドラッグすることで角度を変えてview階層を見ることができます。

# View Controls

![スクリーンショット 2016-12-04 14.09.31.png](https://qiita-image-store.s3.amazonaws.com/0/100736/466e06c0-ca34-a37e-977a-889743a4dd91.png)
これらのボタンの意味を左から1つずつ説明します。

## ![スクリーンショット 2016-12-04 14.09.31 2.png](https://qiita-image-store.s3.amazonaws.com/0/100736/d48d576d-203c-491d-0514-17853dc88444.png) view間の間隔調節

一番左のバーをいじることでview間の間隔を調整することができ、個々のviewが見やすくなります。

![スクリーンショット 2016-12-04 14.29.14.png](https://qiita-image-store.s3.amazonaws.com/0/100736/9ec87f21-d6eb-dca5-c1c3-f5f9de422dd4.png)　　![スクリーンショット 2016-12-04 14.29.31.png](https://qiita-image-store.s3.amazonaws.com/0/100736/e5d3d42c-5a42-4ee2-448a-f8c75c793886.png)

## ![スクリーンショット 2016-12-04 14.09.31 2.png](https://qiita-image-store.s3.amazonaws.com/0/100736/c8a74b91-6694-a083-3205-357f1cdfb548.png) クリップされたviewの表示

画面外にレイアウトされたオブジェクトはデフォルトだと表示されないので、表示したい場合はこのShow Clipped Contentをクリックします。

![スクリーンショット 2016-12-04 15.48.18.png](https://qiita-image-store.s3.amazonaws.com/0/100736/8167c5c6-78bc-1aea-df84-21e902458c53.png)　　![スクリーンショット 2016-12-04 15.48.28.png](https://qiita-image-store.s3.amazonaws.com/0/100736/b5fdf6a9-c90b-f2a2-b389-b1b1be526830.png)

## ![スクリーンショット 2016-12-04 14.09.31 2.png](https://qiita-image-store.s3.amazonaws.com/0/100736/aa8e702f-0cd4-b728-99aa-db9a9b5fe020.png) 制約の表示

このShow Constraintsをクリックした後に任意のオブジェクトをクリックするとそのオブジェクトについている制約が表示されます。

![スクリーンショット 2016-12-04 16.04.13.png](https://qiita-image-store.s3.amazonaws.com/0/100736/c08724d8-1cd3-a1fe-71f7-ce52088ef9e1.png)

右ペインのsize inspectorで制約の具体的数値を確認することができます。

## ![スクリーンショット 2016-12-04 14.09.31 2.png](https://qiita-image-store.s3.amazonaws.com/0/100736/00bb593c-256d-bbd5-c6db-df4b6486ef2d.png) 表示モードの変更

![スクリーンショット 2016-12-04 16.36.21.png](https://qiita-image-store.s3.amazonaws.com/0/100736/181652b7-3749-ca90-a321-7a78832dad0e.png)
Contentsモード、Wireframesモード、Wireframes and Contentsモードの3種類があります。

| Contents | Wireframes | Wireframes and Contents |
|:-:|:-:|:-:|
| ![スクリーンショット 2016-12-04 16.37.45.png](https://qiita-image-store.s3.amazonaws.com/0/100736/31cbf3c6-b999-84c0-d61a-122971cb4f8a.png)  | ![スクリーンショット 2016-12-04 16.38.01.png](https://qiita-image-store.s3.amazonaws.com/0/100736/fd0df0aa-f737-bddc-4486-5a5ebf734436.png)  | ![スクリーンショット 2016-12-04 16.38.21.png](https://qiita-image-store.s3.amazonaws.com/0/100736/0c905897-c09c-2f3f-b04f-780d34730fb6.png)
  |

## ![スクリーンショット 2016-12-04 14.09.31 2.png](https://qiita-image-store.s3.amazonaws.com/0/100736/604e1b98-46cd-8b8c-5943-22fb23896c9a.png) ![スクリーンショット 2016-12-04 16.44.01.png](https://qiita-image-store.s3.amazonaws.com/0/100736/6ff58622-f264-60ed-aac1-ad38484cfaf1.png) 2D⇔3D表示の切り替え

現在2Dの場合は3Dに、3Dの場合は2Dに表示を切り替えるボタンです。

## ![スクリーンショット 2016-12-04 14.09.31 2.png](https://qiita-image-store.s3.amazonaws.com/0/100736/547d5292-6703-e9a8-4ca3-820b128b3115.png) 拡大縮小

このボタンを使うか、トラックパッドでピンチそうさを行うか、オプションキーを押しつつマウスを上下にスクロールすれば拡大縮小操作ができます。

## ![スクリーンショット 2016-12-04 14.09.31.png](https://qiita-image-store.s3.amazonaws.com/0/100736/3b5332a9-1949-f995-3cbb-307d1aba30f7.png) z軸方面のviewの表示調整

![スクリーンショット 2016-12-04 17.07.54.png](https://qiita-image-store.s3.amazonaws.com/0/100736/15521eed-ede7-0822-d194-74ba08fcfeca.png)　　![スクリーンショット 2016-12-04 17.08.19.png](https://qiita-image-store.s3.amazonaws.com/0/100736/8c3b8153-9244-bea0-3ab0-2e3a9f89e64b.png)

# オプション

「オプション」と称していいのかわかりませんが、右クリックをした時に表示される各項目について説明します。

## Print Description of {viewObject}

選択したviewをpoコマンドで出力した時と同様の操作を行うことができます。

```text:実施例
Printing description of $136:
<UIView: 0x7fedba408950; frame = (200 150; 50 150); layer = <CALayer: 0x6080000296a0>>
```

## Focus on {viewObject}

選択したviewとそのサブviewだけが見えている状態になります。
下の例で茶色のviewはその上に黄色のview、さらにその上にオレンジのviewがサブviewとしてある状態なので、茶色のviewにFocus on UIViewを適用すると右のスクショの状態になります。

![スクリーンショット 2016-12-04 19.04.00.png](https://qiita-image-store.s3.amazonaws.com/0/100736/be14b149-7cc6-68e5-c68e-06da2d88bea7.png)　　![スクリーンショット 2016-12-04 19.04.22.png](https://qiita-image-store.s3.amazonaws.com/0/100736/48a8c421-6af1-76f5-18ac-168baa9ea2fe.png)

## Show Constraints

選択したviewオブジェクトについている制約を表示することができます。細かい数値は右ペインのsize inspectorで見ることができます。機能としては先程のShow Constraintsボタンをクリックしたときと同様です。

## Hide Views in Front / Hide Views Behind

選択したviewより前の階層、もしくは後ろの階層のviewを隠します。
下の例では茶色のviewを基準にしてHide Views in Front / Hide Views Behindを実行しています。

| Hide Views Behind | デフォルト | Hide Views in Front |
|:-:|:-:|:-:|
| ![スクリーンショット 2016-12-04 19.34.14.png](https://qiita-image-store.s3.amazonaws.com/0/100736/ed954f68-a2e1-3805-9da6-9061670d3a7f.png)  | ![スクリーンショット 2016-12-04 19.28.18.png](https://qiita-image-store.s3.amazonaws.com/0/100736/58bb2ff5-f5ef-ca33-f1ed-ff7ed4a9add6.png)  | ![スクリーンショット 2016-12-04 19.33.57.png](https://qiita-image-store.s3.amazonaws.com/0/100736/d71ca436-ec95-25fc-37b3-85fbfc845f17.png)  |

# debug navigator

デバッガービューがアクティブの時、debug navigatorには全てのviewオブジェクトが表示されています。親、子、兄弟関係がわかるので、メインウィンドウでの操作よりviewを見つけやすくなります。
左ペインで任意のviewを選択すると、メインウィンドウで該当するviewが薄く色づきます（赤いviewがちょっと青くなってます）。
![スクリーンショット 2016-12-04 20.21.45.png](https://qiita-image-store.s3.amazonaws.com/0/100736/6cab4fee-a5ed-8cd7-90c6-65b5d53a6145.png)

## filter bar

左ペインの一番下にfilter barがありますが、そこには2つのフィルターボタンが存在しています。
![スクリーンショット 2016-12-04 20.32.27.png](https://qiita-image-store.s3.amazonaws.com/0/100736/42dc6571-7114-af1f-140a-a039571031c9.png)

### Show primary views

このフィルターはアプリのコントロール下にない2つめのビューオブジェクトを隠すものです。例えばUIButtonの場合後ろのviewとUILabelで構成されているので、フィルターがONになっている時は1つのviewしか見えません。フィルターがOFFになっている時は中央の3Dエリアでサブビューも見えている状態になります。
…と思っていたのですが想定通りになりません。Xcode7で試しても同じでした。何かご存知の方は編集リクエストやコメントをいただけると幸いです。

### Show only displayed views

このフィルターがかかっていると見えないviewは左ペインで表示されません。つまりisHiddenがtrueになっていたら見えません。
下の例では右がフィルターON、左がフィルターOFFの状態です。buttonのisHiddenをtrueにしているので、フィルターがONの時は見えていません。
![スクリーンショット 2016-12-05 0.12.57.png](https://qiita-image-store.s3.amazonaws.com/0/100736/1c83a555-1ddb-129a-cd56-a9311fcf9dc2.png)![スクリーンショット 2016-12-05 0.12.45.png](https://qiita-image-store.s3.amazonaws.com/0/100736/e1326c2e-192c-88fd-1d49-0aa24e6c8847.png)

### text filter

左ペインに表示されているviewをテキスト情報で絞り込みたい時に使います。単純にクラス名はもちろんのこと、ボタンタイトル、メモリアドレスでの絞り込みにも対応しています。クラス名で入力した場合、サブクラスも表示されるようになっています。
**■ボタンタイトル**
![スクリーンショット 2016-12-11 20.13.46.png](https://qiita-image-store.s3.amazonaws.com/0/100736/5f4925db-8f44-bf42-ebb3-afcd37e5bf6e.png)
**■メモリアドレス**
![スクリーンショット 2016-12-11 20.13.25.png](https://qiita-image-store.s3.amazonaws.com/0/100736/6734164e-1c46-b5f3-bbdd-199ed5366e6a.png)
**■サブクラス表示**
![スクリーンショット 2016-12-11 20.29.11.png](https://qiita-image-store.s3.amazonaws.com/0/100736/96a14302-bd9a-07a9-b989-25464702dd9f.png)


## debug navigatorが役に経った例

実際の業務で役に立った例を紹介します。
画面全体を覆っているviewをremoveFromSuperView()してそのviewとその上に乗っかっているviewを取り除こうと思ったのですが剥がれて欲しいviewがくっついたままでした。茶色いviewのセットも剥がれてほしいのになぜか剥がれていないという状況でした。

| 初期状態 | removeFromSuperView()後 |
|:-:|:-:|
|![スクリーンショット 2016-12-09 11.14.49.png](https://qiita-image-store.s3.amazonaws.com/0/100736/c2255db7-faff-2383-8521-cd2a30b0a786.png)|![スクリーンショット 2016-12-09 11.16.11.png](https://qiita-image-store.s3.amazonaws.com/0/100736/03420f3d-89e1-be02-ecf4-cc39d526e8ce.png)|

3Dのエディタをぐるぐる回してみてもgrayのviewに乗っかっているように見えて「はて？」と思っていたのですが、debug navigatorを見たらすぐ原因がわかりました。
![スクリーンショット 2016-12-09 11.32.48.png](https://qiita-image-store.s3.amazonaws.com/0/100736/19a82c77-eb94-750e-a396-f661dd9e0aa5.png)

brown viewはgray viewにくっついているわけではなくself.viewにくっついているということがひと目でわかりました。

# オブジェクト、サイズインスペクター

左ペインもしくは中央のエディタでオブジェクトを選択すると、オブジェクトインスペクタ、サイズインスペクタに属性値が読み込まれます。オブジェクトインスペクタはそのオブジェクトが持っている特性値を表示し、サイズインスペクタはそのオブジェクトのサイズ情報やAutoLayoutの制約情報を表示します。

# アシスタントエディタ

アシスタントエディタは下図右上の丸が2つ重なったボタンをクリックすることでON/OFFの設定ができます。アシスタントエディタを自動モードに設定すると、選択したビューオブジェクトのソースが表示されます。下図では緑色のviewを選択しているのでUIViewのヘッダが表示されています。
![スクリーンショット 2016-12-06 23.51.12.png](https://qiita-image-store.s3.amazonaws.com/0/100736/6d66bd05-fa30-72a4-04ca-bebb872779f4.png)

# その他Tips

## debug navigatorの表示ショートカット

中央のメインウィンドウでviewや制約を選択した状態でCommand + Shift + Dをすると選択したviewがハイライトされた状態で左ペインのdebug navigatorに表示されます。

## 曖昧なレイアウトの警告

ビューデバッガー表示中に曖昧なレイアウトがあるとこのように紫のビックリマークが表示されます。この紫ビックリマークのRuntime issuesはXcode8から出てきました。スレッド周り、UI周り、メモリ周りの問題を指摘してくれます。
![スクリーンショット 2016-12-09 11.40.39.png](https://qiita-image-store.s3.amazonaws.com/0/100736/4d55e44c-dc84-574c-2f99-de344c33dc79.png)
クリックするとこんな表示が出てきます。
![スクリーンショット 2016-12-09 11.44.32.png](https://qiita-image-store.s3.amazonaws.com/0/100736/687ca492-bc49-7ab9-fbfd-abd74aa62265.png)
どうやら縦方向の位置が曖昧らしいです。
debug navigatorで警告表示をクリックすると該当のview（今回はオレンジ色のview）が青くハイライトされます。
![スクリーンショット 2016-12-09 11.46.59.png](https://qiita-image-store.s3.amazonaws.com/0/100736/ac1c6b52-c537-f498-994a-5960141526e6.png)
この紫ビックリマークはdebug navigatorでも表示されますし、size inspectorでどのように曖昧なのか教えてくれます。
![スクリーンショット 2016-12-11 20.48.45.png](https://qiita-image-store.s3.amazonaws.com/0/100736/18b17da8-e5b7-4ef6-cc6c-110c36368f5a.png)