1. ホーム
  2. ios

[解決済み] addChildViewControllerは実際に何をするのですか?

2022-12-06 10:06:40

質問

私はiOS開発に初めて足を踏み入れたところですが、最初にやらなければならないことのひとつは カスタム コンテナ ビュー コントローラー - と呼ぶことにします。 SideBarViewController - で、表示する子ビューコントローラを入れ替えることができます。 タブバーコントローラ . (これはかなり タブバーコントローラ のようなものですが、タブバーの代わりに隠すことのできるサイドメニューがあります)。

Apple のドキュメントの指示に従い、私は addChildViewController を呼び出します。で表示されている現在の子ビューコントローラーを入れ替えるための私のコードは SideBarViewController で表示されている現在の子ビューコントローラーを入れ替えるための私のコードは次のようになります。

- (void)showViewController:(UIViewController *)newViewController {
    UIViewController* oldViewController = [self.childViewControllers 
                                           objectAtIndex:0];
    
    [oldViewController removeFromParentViewController];
    [oldViewController.view removeFromSuperview];
    
    newViewController.view.frame = CGRectMake(
        0, 0, self.view.frame.size.width, self.view.frame.size.height
    );
    [self addChildViewController: newViewController];
    [self.view addSubview: newViewController.view];
}

それから、私は addChildViewController がここで何をしているのかを理解しようとして、私は全くわからないことに気づきました。新しい ViewController.childViewControllers という配列がありますが、何の効果もないようです。子コントローラのビューからストーリーボードに設定した子コントローラへのアクションやアウトレットは、たとえ addChildViewController を呼び出さなくても、ストーリーボードに設定した子コントローラのビューからのアクションやアウトレットは正常に動作しています。

確かに、もし私がコードを書き換えて addChildViewController を呼び出さず、代わりにこのように書くと...

- (void)showViewController:(UIViewController *)newViewController {

    // Get the current child from a member variable of `SideBarViewController`
    UIViewController* oldViewController = currentChildViewController;

    [oldViewController.view removeFromSuperview];

    newViewController.view.frame = CGRectMake(
        0, 0, self.view.frame.size.width, self.view.frame.size.height
    );
    [self.view addSubview: newViewController.view];

    currentChildViewController = newViewController;
}

...それから、私のアプリは、私の知る限り、まだ完全に動作しています!

Apple のドキュメントでは、どのような addChildViewController が何をするのか、またはなぜそれを呼び出すことになっているのかについて、Apple のドキュメントはあまり光を当てていません。メソッドが何をするか、またはなぜそれを使用しなければならないかについての関連する説明の全範囲が UIViewController クラス リファレンス は、現時点では

指定されたビューコントローラを子として追加します。 ... このメソッドは、カスタムコンテナのビューコントローラの実装からコールされることのみを想定しています。このメソッドをオーバーライドする場合は、実装の中で super を呼び出す必要があります。

同じページの前の方にこんな段落もあります。

<ブロッククオート

コンテナビューコントローラは、子ビューのルートビューをビュー階層に追加する前に、子ビューコントローラを自分自身と関連付ける必要があります。これにより、iOS は子ビューコントローラとそのコントローラが管理するビューに適切にイベントをルーティングすることができます。同様に、子ビューのルートビューをビュー階層から削除した後は、その子ビューコントローラを自分自身から切り離さなければなりません。これらの関連付けを行ったり解除したりするために、 コンテナは基底クラスで定義されている特定のメソッドをコールします。これらのメソッドは、コンテナクラスのクライアントから呼び出されることを意図したものではありません。

以下は、呼び出す必要があるかもしれない必須のメソッドです。

addChildViewControllerです。

removeFromParentViewController

willMoveToParentViewControllerを使用します。

didMoveToParentViewController:

が、このメソッドが言っている「イベント」や「期待される格納動作」が何なのか、なぜ(あるいはいつ)これらのメソッドを呼び出すことが「必須」なのかについての手がかりは何も提供されていません。

Apple のドキュメントの "Custom Container View Controllers" セクションにあるカスタム コンテナ ビュー コントローラーの例はすべてこのメソッドを呼び出しているので、単に子 ViewController を配列にポップする以上の何か重要な目的を果たすと思いますが、その目的が何であるのかがわかりません。このメソッドは何をするのでしょうか、そしてなぜ私はそれを呼び出す必要があるのでしょうか?

どのように解決するのですか?

私もこの質問には疑問を感じていました。私は WWDC 2011のセッション102 のビデオとビューコントローラーさん ブルース・D・ニロ は、このように述べています。

viewWillAppear: , viewDidAppear: などは addChildViewController: . 全ては addChildViewController: がすることは、 "このビューコントローラはその子である" と言うことであり、ビューの外観とは何の関係もないのです。いつ呼び出されるかは、ビューがウィンドウ階層を出入りするときと関連しています。

ということで、どうやら addChildViewController: の呼び出しはほとんど何もしません。呼び出しの副作用が重要な部分です。それらは parentViewControllerchildViewControllers の関係にあります。以下は、私が知っている副作用の一部です。

  • 子ビューコントローラへの外観メソッドの転送
  • 回転メソッドの転送
  • (可能な限り) メモリ警告を転送する
  • 一貫性のない VC 階層を回避すること、特に transitionFromViewController:toViewController:… で、両方のVCが同じ親を持つ必要がある場合、特に
  • カスタム コンテナ ビュー コントローラが状態の保存と復元に参加することを許可する。
  • レスポンダチェーンに参加する
  • レスポンダのフックアップ navigationController , tabBarController などのプロパティ