topLayoutGuideが曖昧(AMBIGUOUS)でハマるケース


概要
====
謎のレイアウト崩れ。autolayoutでハマって半日以上浪費したので備忘録。

多分、autolayoutの最適化周りのバグ。view構造をバラして展開してくれるのはいいんだけど、それ故にあっちのアレが明後日の場所でエラーりましたよ、と。


結論としては、

- navigationViewControllerのせいでまだ曖昧なとこがあるうちに
- viewControllerのviewに貼り付けたCustomViewの中で使ってたautolayoutを解決しようとして
- view構造を展開してから解決しようとして
- 曖昧なままのUILayoutGuide（topLayoutGuide）との関係性が生まれ、計算しようとして、エラー。
- エラーったから、適当に解決するね → レイアウト崩れ

ということらしく。

多分タイミングというか依存性解決に失敗してる感あるなあと、試しに
適当なタイミング（viewWillAppear:）でviewControllerに

```objc
self.view.layoutIfNeeded()
```
させておいたら直るという。

ほんと やめて、っていう。


状況
====
いつの間にか、レイアウト崩れが発生している！？
なんかよくわからんけど、autolayoutがエラーって、勝手にConstraintぶっ壊してくれる、、、
なにこれ。

```objc
2018-08-07 16:42:05.366607+0900 HogeFuga Develop[65798:3081762] [LayoutConstraints] Unable to simultaneously satisfy constraints.
	Probably at least one of the constraints in the following list is one you don't want. 
	Try this: 
		(1) look at each constraint and try to figure out which you don't expect; 
		(2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<_UILayoutSupportConstraint:0x600000286180 _UILayoutGuide:0x7f8602071450.height == 0   (active)>",
    "<_UILayoutSupportConstraint:0x6000002858c0 V:|-(0)-[_UILayoutGuide:0x7f8602071450]   (active, names: '|':UIView:0x7f8602069610 )>",
    "<NSLayoutConstraint:0x600000287df0 UIStackView:0x7f8602069800.height == 38   (active)>",
    "<NSLayoutConstraint:0x6000002871c0 V:|-(0)-[HogeFuga.THCalendarWeekdaysView:0x7f8602062bb0]   (active, names: '|':HogeFuga.THCalendarView:0x7f8602062670 )>",
    "<NSLayoutConstraint:0x600000287170 HogeFuga.THCalendarWeekdaysView:0x7f8602062bb0.height == 22   (active)>",
    "<NSLayoutConstraint:0x600000287120 V:[HogeFuga.THCalendarWeekdaysView:0x7f8602062bb0]-(0)-[UICollectionView:0x7f86038c4800]   (active)>",
    "<NSLayoutConstraint:0x6000002882a0 V:[UIStackView:0x7f8602069800]-(0)-[HogeFuga.THCalendarView:0x7f8602062670]   (active)>",
    "<NSLayoutConstraint:0x600000288340 V:[_UILayoutGuide:0x7f8602071450]-(0)-[UIStackView:0x7f8602069800]   (active)>",
    "<NSAutoresizingMaskLayoutConstraint:0x600000090c70 h=-&- v=-&- 'UIView-Encapsulated-Layout-Top' UIView:0x7f8602069610.minY == 0   (active, names: '|':UIViewControllerWrapperView:0x7f8602071d90 )>"
)
Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600000287120 V:[HogeFuga.THCalendarWeekdaysView:0x7f8602062bb0]-(0)-[UICollectionView:0x7f86038c4800]   (active)>
```

読むと、上から下に流れる感じの変哲のないレイアウトで、エラーる要因がない。
[wtfautolayout.com](https://www.wtfautolayout.com/) とかで眺めても、どう見ても正しい。
おかしい。

~~まさか一番上の`_UILayoutGuide:0x7f8602071450 `が悪いとは(ry~~

調べる
====

まずは

```
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
```

と言われるままに
`UIViewAlertForUnsatisfiableConstraints`とかいうシンボルにブレークポイントを設定。

すると、変なとこで引っかかる。

```objc
•UINavigationBar:0x7fd502e0fc90
|   _UIBarBackground:0x7fd502e0c1e0
|   |   UIImageView:0x7fd502e11f60
|   |   UIVisualEffectView:0x7fd502e12190
|   |   |   _UIVisualEffectBackdropView:0x7fd502e5fa90
|   |   |   _UIVisualEffectSubview:0x7fd502e5eec0
|   _UINavigationBarLargeTitleView:0x7fd502e14020'2017年8月'
|   |   UILabel:0x7fd502e15390
|   •_UINavigationBarContentView:0x7fd502e123f0'2017年8月'
|   |   *<UILayoutGuide: 0x6080001a6040 - "BackButtonGuide(0x7fd502e129e0)", layoutFrame = {{0, 0}, {24, 44}}, owningView = <_UINavigationBarContentView: 0x7fd502e123f0; frame = (0 0; 375 44); layer = <CALayer: 0x60800002bbc0>>>
|   |   *<UILayoutGuide: 0x6080001a6120 - "LeadingBarGuide(0x7fd502e129e0)", layoutFrame = {{24, 0}, {0, 44}}, owningView = <_UINavigationBarContentView: 0x7fd502e123f0; frame = (0 0; 375 44); layer = <CALayer: 0x60800002bbc0>>>- AMBIGUOUS LAYOUT for UILayoutGuide:0x6080001a6120'LeadingBarGuide(0x7fd502e129e0)'.minX{id: 610}, UILayoutGuide:0x6080001a6120'LeadingBarGuide(0x7fd502e129e0)'.Width{id: 613}
|   |   *<UILayoutGuide: 0x6080001a6200 - "TitleView(0x7fd502e129e0)", layoutFrame = {{24, 0}, {343, 44}}, owningView = <_UINavigationBarContentView: 0x7fd502e123f0; frame = (0 0; 375 44); layer = <CALayer: 0x60800002bbc0>>>- AMBIGUOUS LAYOUT for UILayoutGuide:0x6080001a6200'TitleView(0x7fd502e129e0)'.minX{id: 612}, UILayoutGuide:0x6080001a6200'TitleView(0x7fd502e129e0)'.Width{id: 616}
|   |   *<UILayoutGuide: 0x6080001a62e0 - "TrailingBarGuide(0x7fd502e129e0)", layoutFrame = {{367, 0}, {0, 44}}, owningView = <_UINavigationBarContentView: 0x7fd502e123f0; frame = (0 0; 375 44); layer = <CALayer: 0x60800002bbc0>>>- AMBIGUOUS LAYOUT for UILayoutGuide:0x6080001a62e0'TrailingBarGuide(0x7fd502e129e0)'.minX{id: 615}, UILayoutGuide:0x6080001a62e0'TrailingBarGuide(0x7fd502e129e0)'.Width{id: 619}
|   |   *<UILayoutGuide: 0x6080001a63c0 - "UIViewLayoutMarginsGuide", layoutFrame = {{16, 0}, {343, 44}}, owningView = <_UINavigationBarContentView: 0x7fd502e123f0; frame = (0 0; 375 44); layer = <CALayer: 0x60800002bbc0>>>
|   |   *UILabel:0x7fd502f42300'2017年8月'
|   +_UINavigationBarModernPromptView:0x7fd502e19fb0
|   |   *UILabel:0x7fd502e1a4e0
```

`AMBIGUOUS LAYOUT for UILayoutGuide`と出てるのが、autolayout的に曖昧なトコロ。

これ、どういうこと？
関係あるの？とちゃんと見比べていれば、あるいはすぐ問題解決できたかもしれません。
どゆこと？と他に理由を探したのが間違い。


わからないので、一番怪しそうな`NSAutoresizingMaskLayoutConstraint`を殺すべく、`translatesAutoresizingMaskIntoConstraints`をfalseにしてみてくが
ViewControllerのviewにresizingMask付けなかったらダメじゃん、と、つまり違うらしい。

続いて[AutolayoutGuide::デバッグに役立つヒント](https://developer.apple.com/jp/documentation/UserExperience/Conceptual/AutoLayoutGuide/DebuggingTricksandTips/DebuggingTricksandTips.html)とかを眺めつつ
デバッガコンソールで`constraintsAffectingLayoutForAxis `とかを叩くも、返ってくるのは期待してる通りの正常っぽい結果。

もはや誰が敵かわからなくなり、collectionViewだからいけないのではないか、とか
いやあるいはstoryboardのオプションが、とか色々試し出す。
混乱と疑心暗鬼。

解決
====
以前は動いていた、今は動いてない。
ならば、前の状況に近付けて、切り分けを、、、は面倒なので

代わりに、ばっさばっさとコメントアウトを行い、ちゃんと動く状態を作り出す。
Storyboard上で配置されてる要素を ばっさばっさと捨てながら、動くところまで持っていく。

- 縦方向のレイアウトの問題

なのは自明だったので、それに基づいて、色々試して傾向をみる。

結果的に、上側のConstraintを切るとちゃんと動いたので、ええーっと、となり
それまで試したCompressionResistancePriorityなり
intrinsicContentSizeを設定してみたりと努力は無駄でした。ちゃんちゃん。

topLayoutGuideとかOS(ランタイム)側がよしなにしてくれるトコの認識だから
まさかそんなのが悪いとか思い付かなかったよ・・・

再現性
====

もう精魂果てたので、誰か暇なら再現性確認してバグレポート投げて、、、