エラー状況
Unbalanced calls to begin/end appearance transitions
エラーでぐぐると、「viewDidLoad
やviewWillAppear
内で画面遷移をしているのが原因」なパターンが多くヒットする。
が、それをしていないのに起きる時のはなし。
エラーが発生したコード
簡略版。こんな感じのコードで起きた。
class ViewController {
override func viewDidLoad() {
super.viewDidLoad()
getTimeline() // サーバーから取得したデータをもとに、非同期でViewをreloadする
}
// 子のViewControllerを返す処理。
// XLPagerTabStripというライブラリを使用してます。
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
return [hogeVC(),fugaVC()]
}
}
ポイントは2つ。
- ViewController内に、ContainerViewでViewControllerの子供を持つ
- viewDidLoad
内で通信処理を呼び出し、その中でViewを更新している
そもそもこのエラーの原因は?
Unbalanced calls to begin/end appearance transitions
は、親のViewControllerの表示が確定していない状態で、子のViewControllerを扱うことで生じる ことがほとんど。
よって、先の例で言えばgetTimeline()
が元凶である。
なぜなら、viewDidLoadを抜けた後にViewのreloadが走り、それが終わることで初めて表示が確定する仕様になっており、その確定の前にviewControllers
が呼ばれてしまうから。
解決策
非同期でViewを更新する処理を、viewDidAppear
に移す。
先の例で言えば、こうすれば解決する。
class ViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
getTimeline() // サーバーから取得したデータをもとに、非同期でViewをreloadする
}
override func viewControllers(for pagerTabStripController: PagerTabStripViewController) -> [UIViewController] {
return [hogeVC(),fugaVC()]
}
}
ただし、Appear後に非同期処理を開始するのが不満な場合は、異なる策をとる必要がある。