はじめに
iOS5からUIViewControllerを自前のクラスにaddChildViewController:メソッドで追加できるようになった。
最近では、こういった自前コンテナは主にFacebookやPath2.0のスライドメニュー風のUI開発なんかに使われていると思う。
このaddChildViewController:メソッドの後には必ずdidMoveToParentViewController:メソッドを呼ぶという説明があるが、これの意味がよくわからなかったのでそのメモ。
例えば
didMoveToParentViewControllerの必要性を疑うコード
//自前コンテナ(self)にchildViewControllerを追加
[self addChildViewController:childViewController];
//その後didMoveToParentViewControllerを実行しなければいけない
[childViewController didMoveToParentViewController:self];
この追加(add)したあとになぜ完了(didMove)を明示的に知らせないといけないのか謎という感覚。また、これがなくてもこちらの想定通り動くのでずっと疑問だった。
結論としては
自前コンテナでaddChildViewController:を実行した後は、やはり必ずdidMoveToParentViewController:を呼ぶ。
説明
UIViewControllerの追加サイクル
そもそもUIViewControllerの追加には「開始」と「終了」がかならずセットで必要となる。
・追加: addChildViewController:
・開始: willMoveToParentViewController:(add後に自動で呼ばれる)
・完了: didMoveToParentViewController:(任意のタイミングで呼ぶ)
・開始: willMoveToParentViewController:(add後に自動で呼ばれる)
・完了: didMoveToParentViewController:(任意のタイミングで呼ぶ)
まず自前コンテナへの追加のためにaddChildViewController:した際に、ViewControllerの追加開始の合図であるwillMoveToParentViewControler:は自動で呼ばれる。
開始は自動で呼ばれるが、それが終了したことをコールするためのdidMoveToParentViewController:メソッドは自動で呼ばれないため必要となる。
終了をコールしないと何に困るのか
もともとUIViewControllerは自身が他のコンテナに追加(もしくは削除)されている最中かどうかを知ることで処理を分岐する事もできるようになっていて、これを判断するのに完了を呼ぶ必要がある。
ちなみに、追加されている途中かどうかはUIViewControllerのisMovingToParentViewControllerメソッドによって取得できる。
didMoveToParentViewController:がなぜ自動で呼ばれないようになっているか
では、なぜdidMoveToParentViewController:が自動で呼ばれないかというと、画面遷移にトランジションを指定したい場合が想定されているからだと思う。
例えば次のコードのように、完了までに時間がかかる(実装者が時間を指定できる)場合に、完了のメソッドが明示的にコールできるようになっていることでその意味が出てくる。
/*fromViewControllerはすでにコンテナに追加されているとする*/
//toViewControllerをコンテナに追加する
[self addChildViewController:toViewController];
//fromからtoへ画面遷移のトランジションを行う
[self transitionFromViewController:fromViewController
toViewController:toViewController
duration:1.0
options:UIViewAnimationOptionTransitionNone
animations:^{
// ここで何かしらの遷移アニメーション
}
completion:^(BOOL finished) {
// 追加完了を明示的に行う
[toViewController didMoveToParentViewController:self];
}];
まとめ
上記のように、画面遷移のトランジションを使わなくてもaddChildViewController:したらdidMoveToParentViewController:を呼び出すことを忘れないようにしたらよいでしょう。
もし、突っ込みどころ等あればコメントなり編集リクエストでお願いします。
参考
isMovingToParentViewControllerメソッドについてはiOS View Controllerカタログの「ナビゲーションスタックの変化の監視」
https://developer.apple.com/jp/devcenter/ios/library/documentation/ViewControllerCatalog.pdf
https://developer.apple.com/jp/devcenter/ios/library/documentation/ViewControllerCatalog.pdf
コメント
コメントを投稿