テストケースの実装内容
テストケースは以下のように、ParentとChildをNavigation Controllerでつなげたシンプル構成。
先にコードを載せておく。なお、ChildViewControllerは下記ParentをChildに変更したものとほぼ変わらないので省略する。各メソッドが具体的にどういったものなのかは、末尾に参考記事を載せているのでそれらを参照されたし。
import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("Parent: viewDidLoad")
}
override func viewWillAppear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("Parent: viewWillAppear")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("Parent: viewDidAppear")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Parent: viewWillDisappear")
}
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
print("Parent: viewDidDisappear")
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
print("Parent: viewDidLayoutSubviews")
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
print("Parent: viewWillLayoutSubviews")
}
@IBAction func goChildButtonTapped(_ sender: Any) {
performSegue(withIdentifier: "goChild", sender: nil)
}
}
テスト
動画のように画面遷移したとき、
-
Simulator起動(Parentを表示)
Parent: viewDidLoad
Parent: viewWillAppear
Parent: viewWillLayoutSubviews
Parent: viewDidLayoutSubviews
Parent: viewWillLayoutSubviews
Parent: viewDidLayoutSubviews
Parent: viewDidAppear -
Childへ移動
Child: viewDidLoad
Parent: viewWillDisappear
Child: viewWillAppear
Child: viewWillLayoutSubviews
Child: viewDidLayoutSubviews
Parent: viewDidDisappear
Child: viewDidAppear -
Parentに戻る
Child: viewWillDisappear
Parent: viewWillAppear
Parent: viewWillLayoutSubviews
Parent: viewDidLayoutSubviews
Child: viewDidDisappear
Parent: viewDidAppear -
Childへ移動(2と同じ)
Child: viewDidLoad
Parent: viewWillDisappear
Child: viewWillAppear
Child: viewWillLayoutSubviews
Child: viewDidLayoutSubviews
Parent: viewDidDisappear
Child: viewDidAppear -
Parentに戻るスワイプを途中で戻す
Child: viewWillDisappear
Parent: viewWillAppear
Child: viewWillAppear
Child: viewDidAppear
知見の利用
たとえば、スワイプキャンセル(5番)では実行してほしくないが、完全にParentへ戻ったとき(3番)は実行してほしい場合、3番から5番のうち被っているものを除いて(あとviewWillLayoutSubviews
はレイアウト系ライフサイクルメソッド(参考:UIViewControllerのライフサイクル - Qiita)なので省略)
Child: viewDidDisappear
Parent: viewDidAppear
のどちらかということに、とりあえずはなる。さらにここからChildへ移動する場合(4番)は実行したくない場合、
Child: viewDidDisappear
だけが生き残る。さーらーに、Parentへ戻ったとき(3番)に上記を実行したあとで何かを実行したい場合は、3番からChild: viewDidDisappear
よりあとのメソッドを探して
Parent: viewDidAppear
に白羽の矢が立つ。
実際は、上記メソッドと何らかのブーリアンを組み合わせてうまいことやるのかしら。そのままviewDidDisappear
でUITableView.reloadData()
とかすると、一度画面が写りきってから更新されるので見目麗し……くない。
まとめ
とりあえず現状の問題はこの知見をもとに解決できた。場当たり的だが、動けばいいんだよ。
スマホに入れているアプリを見ても、一度画面が写ってから更新されるような挙動をしているものなどない。どうやって実装しているのだろう。と考えだしたらGitHubの旅に出たほうがいいのか。まあそのうち気が向いたら笑
ここでは基本的なメソッドに限定したが、各挙動に対してトグル変化するブーリアンもいるので(参考:[開発者向け] UINavigationController と生きていく: ヒコザレポート)、これらも考え出すとグロいことになってくる。