はじめに
こちらの記事は以前ツイートした(↓)内容を元にしています。だいぶ時間がたっているのですが、簡単で有効な方法だと思ったので、グーグル検索にひっかかるようにQiitaにしておきたいと思います。
Xcode11のView Debuggerから、制約も表示されるようになったらしく、AutoLayoutが壊れた時に実行して、ログ出力の0xから始まるメモリアドレスを適当にコピペしてみたら、どのViewや制約で壊れが発生しているのか直ぐ見つけられて捗った。 pic.twitter.com/vYGv9HyKOC
— Teruto Yamasaki ☕️ (@snoozelag) May 28, 2020
手順
AutoLayoutのデバッグでは、ログから問題のビューや制約を把握することが肝要ですが、ビューデバッガー上で問題の箇所を特定し表示できることがわかりました。
以下の3STEPで、Xcodeのログに出力されたAutoLayoutのエラーログのメモリアドレスから、絞り込みができます。
(1) AutoLayoutの「breaking constraint〜」 のエラーログが出力されたら、 探したいビューまたは制約のメモリアドレス(0xからはじまる)をコピーします。
(2) ビューデバッガーを起動します(長方形が互い違いに重なっているボタンです)。この時、ログが出力されたと思われる画面を表示していないと見つかりませんので注意です。
(3) Debug Navigatorペインの下部にある、入力フィールドに先ほどコピーしたメモリアドレスをペーストします。
この時、ビューツリーの最も下にある要素が、問題の起きたビューまたは制約になります。(特定をすることができました!)
結果がでない場合、すでに画面上からそのインスタンスが削除されている可能性があります。別の画面での発生したログでないか確認しましょう。ログが表示された直後にビューデバッガーを起動するのがコツです。
ーーー
おまけ(解決編)
(4) ビューデバッガーのハイライト機能などを活用し、このビューに関連する制約を確認し、競合を解決します。
・ビューツリー上のオブジェクトは「副次クリック>Print Description〜」で詳細をログ出力できます。
・ビューツリー上のビューや制約は、選択するとビューデバッガーの表示上にハイライト(濃い青色)になります。
例えば、上記の画像のサンプルでは、同じUIViewに対して、[高さ31の制約][高さ80の制約]と、同じ優先度で競合する制約を設定しているため、[高さ80の方の制約に対して「Will attempt to recover by breaking constraint.(制約を解除して回復を試みる)」と出ています。
この場合、どちらかの制約をコードから削除する、または優先度を設定することでエラーは解決されました。
おわりに
いかがでしたでしょうか。
Storyboard(Xib)でレイアウトを設定する場合には、ほとんどのエラーが即座に可視化されますので、その場で問題の修正が行えます。しかし、コードで追加した場合や、システム側のUIの制約と競合した時にはどうでしょうか。(難しいことが多いです。)
今回の方法では、多少ビューデバッガーの起動が重たいのはしょうがないとして、このテクニックに気付いてから、かなり活用するようになりました。
また、ツイートではXcode11以降からと書いたのですが、Xcode10.3で確認したところも問題なくビューデバッガー上に制約が表示され、同様のテクニックが有効でした。もちろんXcode12でも使えます。
以上、参考になれば嬉しいです。それでは、良きデバッグライフを!