web-dev-qa-db-ja.com

ストーリーボード-AppDelegateのViewControllerを参照

次のシナリオを検討してください。ストーリーボードベースのアプリを持っています。 ViewControllerオブジェクトをストーリーボードに追加し、このViewControllerのクラスファイルをプロジェクトに追加し、IB IDインスペクターで新しいクラスの名前を指定します。 AppDelegateからこのViewControllerをプログラムでどのように参照しますか?関連するクラスで変数を作成し、それをIBOutletプロパティに変更しましたが、コードで新しいViewControllerを参照できる方法がありません-接続をCtrlキーを押しながらドラッグしようとしても機能しません。

つまり、AppDelegate内で、次のようにベースViewControllerにアクセスできます。

(MyViewController*) self.window.rootViewController

しかし、ストーリーボードに含まれる他のViewControllerはどうですか?

121
Matthias D

-[UIStoryboard instantiateViewControllerWithIdentifier:]の-​​ ドキュメント をご覧ください。これにより、IB Attributes Inspectorで設定した識別子を使用して、ストーリーボードからView Controllerをインスタンス化できます。

enter image description here

サンプルコードを追加するために編集:

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"MainStoryboard"
                                                         bundle: nil];

MyViewController *controller = (MyViewController*)[mainStoryboard 
                    instantiateViewControllerWithIdentifier: @"<Controller ID>"];
165

XCode 5を使用する場合は、別の方法で実行する必要があります。

  • UIViewControllerUIStoryboardを選択します
  • 右上のペインのIdentity Inspectorに移動します
  • Use Storyboard IDチェックボックスをオンにします
  • Storyboard IDフィールドに一意のIDを書き込みます

次に、コードを記述します。

// Override point for customization after application launch.

if (<your implementation>) {
    UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:@"Main" 
                                                             bundle: nil];
    YourViewController *yourController = (YourViewController *)[mainStoryboard 
      instantiateViewControllerWithIdentifier:@"YourViewControllerID"];
    self.window.rootViewController = yourController;
}

return YES;
41
Faruk Toptas

一般的に、システムはストーリーボードを使用してView Controllerのインスタンス化を処理する必要があります。必要なのは、ストーリーボードを適切に設定していれば、すでに正しく初期化されているはずのView Controllerを初期化するのではなく、self.window.rootViewControllerへの参照を取得してviewController階層をトラバースすることです。

したがって、あなたのrootViewControllerがUINavigationControllerであり、そのトップビューコントローラーに何かを送信したい場合、AppDelegateのdidFinishLaunchingWithOptionsで次のようにします。

UINavigationController *nav = (UINavigationController *) self.window.rootViewController;
MyViewController *myVC = (MyViewController *)nav.topViewController;
myVC.data = self.data;

Swiftのifは非常に似ています:

let nav = self.window.rootViewController as! UINavigationController;
let myVC = nav.topViewController as! MyViewController
myVc.data = self.data

ストーリーボードの通常のロード方法をバイパスして、ストーリーボード全体を自分でロードする場合を除き、アプリデリゲートからのストーリーボードIDを使用してView Controllerを初期化するべきではありません。 AppDelegateからシーンを初期化する必要がある場合、おそらく何か間違ったことをしている可能性があります。何らかの理由で、スタックを介してView Controllerにデータを送信したい場合、AppDelegateがView Controllerスタックに到達してデータを設定することはないはずです。それはビジネスではありません。それがビジネスであるのはrootViewControllerです。 rootViewControllerに独自の子を処理させます!したがって、info.plistファイル内の参照を削除することにより、システムによる通常のストーリーボードのロードプロセスをバイパスする場合、せいぜいinstantiateViewControllerWithIdentifier:を使用してrootViewControllerをインスタンス化し、コンテナの場合はそのルート、 UINavigationControllerのように。避けたいのは、ストーリーボードによって既にインスタンス化されているView Controllerをインスタンス化することです。これはよく見かける問題です。要するに、私は受け入れられた答えに同意しません。ポスターがストーリーボードのロードをinfo.plistから削除することを意味しない限り、それは間違っています。システムがルートシーンを初期化してウィンドウに割り当てたため、おそらくメモリリークではありませんが、その後になって、再びインスタンス化して再度割り当てました。あなたのアプリはかなり悪いスタートを切っています!

8
smileBot
    UIStoryboard * storyboard = [UIStoryboard storyboardWithName:@"Tutorial" bundle:nil];
    self.window.rootViewController = [storyboard instantiateInitialViewController];
0
Ofir Malachi