web-dev-qa-db-ja.com

AppDelegate、RootViewController、およびUIApplicationの間の関係は何ですか?

Appdelegate、RootViewControoler、およびUIApplicationの間の関係を理解し​​ようとしています。これが私がこれまでにちょっと理解したことです:

アプリケーションを起動すると、main.mがロードされます。

ここから、MainWindow.xibがロードされます。

MainWindow.xibでは、ファイルの所有者はUIApplicationタイプです。

UIApplicationのデリゲートをAppDelegateに設定します。

AppDelegateのソースコードで、RootViewControllerを最初に表示されるビューに設定できます。

これは正しいですか? AppDelegateに最初に実行するように促すものは

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { }

方法?

25
guy8214

Objective-Cアプリケーションが起動すると、main()という名前の関数を実行することから起動します。ファイル「main.m」にある必要はありませんが、Xcodeウィザードが設定する方法です。

ウィザードで生成されたmain()関数内には、次の行があります。

int retVal = UIApplicationMain(argc, argv, nil, nil);

これが、アプリケーション全体を構成する「UIKit」フレームワークの始まりです。 UIApplicationMain内に、タイプUIApplicationのオブジェクトが作成されます。また、アプリケーションの起動時にUIApplicationが行うことの一部は、UIApplicationクラスのデリゲートメンバーでapplicationDidFinishLaunchingWithOptionsメソッドを呼び出すことです。このデリゲートは、MainWindow.xibファイルで、UIApplicationDelegateプロトコルに準拠するNSObjectのサブクラスであるProjectAppDelegateクラスのインスタンスとして設定されます。

AppDelegateに最初に実行するように促すものは...

MainWindow.xibファイルで接続した(プロジェクトウィザードが実際に接続した)ため、ファイルの所有者(UIApplicationオブジェクト)の「デリゲート」アウトレットを.xibファイルのUIApplicationDelegateオブジェクトとクラスに接続しました。 UIApplicationDelegateのは、アプリのUIApplicationDelegateサブクラスに設定されます。

そして、「MainWindow.xib」には魔法はありません。「Foo.xib」と呼ぶことができます。重要なのは、「Mainnibファイルのベース名」と呼ばれるInfo.plistファイルのプロパティが「MainWindow」であるということです。 MainWindow.xibの名前をFoo.xibに変更し、Info.plistの「Mainnib file base name」を「Foo」に変更しようとすると、それでも機能することがわかります。

編集:RootControllerの詳細

繰り返しますが、いわゆる「RootController」には何の魔法もありません。これは、Xcodeの新しいプロジェクトウィザードによって作成されたUIViewControllerサブクラスの名前です。

ウィザードは、ProjectAppDelegateとProjectViewControllerの2つのクラスのコードをプロジェクトに配置します。 ProjectAppDelegateクラスには、次の2つのアウトレットメンバーが含まれています。

IBOutlet UIWindow *window;
IBOutlet ProjectViewController *viewController;

mainWindow.xibファイルでは、UIWindowとProjectViewControllerの両方のインスタンスが配置され、ProjectAppDelegateの上記のアウトレットに接続されます。

画面に表示されるのは、ProjectAppDelegateクラスの次のコードです。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {    

    // Override point for customization after application launch.

    // Add the view controller's view to the window and display.
    [self.window addSubview:viewController.view];
    [self.window makeKeyAndVisible];

    return YES;
}

繰り返しになりますが、これについて本当に魔法のようなものは何もありません。プロジェクトウィザードは、「ルート」ViewControllerのビューをウィンドウのビューに追加し、ウィンドウを表示するコードを作成しました。 「ルート」ビューコントローラーは.xibファイルで作成され、ProjectAppDelegateアウトレットに接続されました。

ウィザードのファイルを使用せずに、完全に自分でアプリケーションを作成することは非常に有益です。 .xibファイルがどのように機能し、それらがコードオブジェクトにどのように関連するかについて多くを学びます。

44
Bogatyr

IOSアプリの出発点は、常にmain()関数(@bogatyrに感謝)です。これには通常、次のようなコードが含まれています。

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

UIApplicationMainの最後の2つのパラメーターは重要であり、プリンシパルクラス名とアプリケーションデリゲートを指定します。それらがnilの場合、Info.plistはメインウィンドウxib(通常はMainWindow.xib)。

// If nil is specified for principalClassName, the value for NSPrincipalClass
// from the Info.plist is used. If there is no NSPrincipalClass key specified, the
// UIApplication class is used. The delegate class will be instantiated 
// using init.
.. UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);

Xibを介してファイル所有者を設定する必要はなく、このUIApplicationMain関数で直接指定できます。

principalClassNameは、文字列UIApplicationまたはUIApplicationのサブクラスにすることができます。同様に、delegateClassNameはこのメソッドで直接指定できます。ドキュメントにあるように、デリゲートクラスはinitを使用してインスタンス化されます。デリゲートクラス--MyAppDelegateを文字列として指定するとします。

UIApplicationMain(int argc, char *argv[], nil, @"MyAppDelegate");

最初にUIApplicationのインスタンスがインスタンス化され、次に NSClassFromString を使用してこの文字列からデリゲートクラスが作成されます。

デリゲートオブジェクトがインスタンス化され、アプリケーションの準備が整うと、このデリゲートオブジェクトはデリゲートメソッドdidFinishLaunchingWithOptionsを使用して通知されます。

Class delegateClass = NSClassFromString(@"MyAppDelegate");
id <UIApplicationDelegate> delegateObject = [[delegateClass alloc] init];

// load whatever else is needed, then launch the app
// once everything is done, call the delegate object to
// notify app is launched
[delegateObject application:self didFinishLaunchingWithOptions:...];

これは、ペン先が使用されていない場合、UIApplicationがプログラムで処理する方法です。真ん中にペン先を使用することはそれほど違いはありません。

15
Anurag

MainWindow.xibは、info.plistでMain nib file base name。 MainWindow.xibで、ロードする最初のコントローラー(この場合はRootViewController)を定義します。

didFinishLaunchingWithOptions:UIApplicationDelegateプロトコルの一部です。このメソッド(iOS4.0 +の場合)は、アプリケーションの起動時に最初に呼び出されることが常に知られています。

1
WrightsCS

AppDelegateはUIApplicationのデリゲートであるため、UIApplicationクラスがライフサイクル中に投稿するすべての通知をリッスンします。 didFinishLaunching通知はその1つであり、AppDelegateが前述のメソッドを呼び出す原因になります。

1
Eimantas

Universal — iPhone + iPad —アプリの場合、ターゲットの情報パネルで、またはNSMainNibFile~ipadキーとNSMainNibFile~iphoneキーをInfo.plistに追加することにより、各プラットフォームに異なるNIBをロードするように指定できます。または、ターゲットにMainWindow~ipad.xib NIBを追加することもできます。これは、Info.plistのNSMainNibFileキーに基づいて、MainWindow.xibではなくiPadに読み込まれます。

ユニバーサルアプリの制御とカスタマイズがさらに必要な場合は、開始NIBを手動で読み込むことができます。 「ユニバーサル」プロジェクトテンプレートには、このメソッドの定型文が含まれているため、この手法の使用を開始する最も簡単な方法は、ユニバーサルプロファイルを使用して新しいiOSプロジェクトを作成することです。

上記の例では、Main NIB FileInfo.plist(ターゲット設定)に設定されているため、アプリケーションデリゲートが呼び出されたときにNIBが既にロードされています。通常、この設定では、MyAppDelegateオブジェクトもNIBにアーカイブされ(いくつかのIBOutletsを含む)、NIBのFile's OwnerUIApplicationに設定されます。

ユニバーサルプロジェクトで2つの代替レイアウトに対応できるようにするには、メインNIBファイルキーをInfo.plistから除外します。次に、アプリケーションデリゲートオブジェクトをプログラムでUIApplicationMainにインスタンス化します。

#import "MYAppDelegate.h"

int main(int argc, char *argv[])
{
  @autoreleasepool {
    return UIApplicationMain(argc, argv, nil, NSStringFromClass([MYAppDelegate class]));
  }
}

次に、環境と設定を確認し、適切なNIBをapplication:DidFinishLaunchingWithOptions:にロードします。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
  _window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
  // Override point for customization after application launch.
  if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
    _viewController = [[[MYViewController alloc] initWithNibName:@"MYViewController_iPhone" bundle:nil] autorelease];
  } else {
    _viewController = [[[MYViewController alloc] initWithNibName:@"MYViewController_iPad" bundle:nil] autorelease];
  }
  _window.rootViewController = _viewController;
  [_window makeKeyAndVisible];
  return YES;
}

- (void)dealloc {
  [_window release];
  [_viewController release];
  [super dealloc];
}

新しい手順は、ルートMYViewControllerを手動で作成し、適切なNIBをロードすることです。この設定では、File's OwnerMYViewControllerではなく光沢のある新しいUIApplicationです。必要に応じて、MYViewControllerは、アプリケーションデリゲートを使用していた可能性のあるものの多くを採用できます。これは、多くの場合、アプリのコアモデルクラスをカプセル化し、データソースとして機能し、ビューやその他のデリゲートとして機能します。 NIBのもの。

したがって、NIBにはルートUIViewが必要であり、File's Ownerview)のMYViewControllerアウトレットに接続する必要があります。

MYViewControllerのNIBは、MYViewController.viewプロパティに最初にアクセスするまで実際にはロードされないことに注意してください。そうして初めて[MyViewController viewDidLoad]が呼び出されます!これが発生する可能性が最も高いのは、ルートウィンドウに追加するときです。

上記のテンプレートコードでは、ルートUIWindowはアプリデリゲートによってインスタンス化されますが、代わりにNIBに含めることができなかった理由はありません。これを行うことを選択した場合は、注意してください。その場合、NIBのウィンドウのrootViewControllerをファイルの所有者に設定すると、ウィンドウがアクティブ化されたときにコントローラーのビューがウィンドウに追加されます。いずれの場合も、最初のNIBの作成には注意してください。

MYViewControllerでルートを管理する場合、アプリデリゲートは必ずしもルートUIWindowへの参照を持っている必要はありませんが、ルートウィンドウをNIBから除外し、アプリで管理する方が全体的にクリーンな場合があります。デリゲート。

それ以外(!)は、単一プラットフォームのアプローチと大差ありません。

1
Scott Lahteine