Appdelegate、RootViewControoler、およびUIApplicationの間の関係を理解しようとしています。これが私がこれまでにちょっと理解したことです:
アプリケーションを起動すると、main.mがロードされます。
ここから、MainWindow.xibがロードされます。
MainWindow.xibでは、ファイルの所有者はUIApplicationタイプです。
UIApplicationのデリゲートをAppDelegateに設定します。
AppDelegateのソースコードで、RootViewControllerを最初に表示されるビューに設定できます。
これは正しいですか? AppDelegateに最初に実行するように促すものは
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { }
方法?
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ファイルがどのように機能し、それらがコードオブジェクトにどのように関連するかについて多くを学びます。
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がプログラムで処理する方法です。真ん中にペン先を使用することはそれほど違いはありません。
MainWindow.xibは、info.plistでMain nib file base name
。 MainWindow.xibで、ロードする最初のコントローラー(この場合はRootViewController
)を定義します。
didFinishLaunchingWithOptions:
はUIApplicationDelegate
プロトコルの一部です。このメソッド(iOS4.0 +の場合)は、アプリケーションの起動時に最初に呼び出されることが常に知られています。
AppDelegate
はUIApplicationのデリゲートであるため、UIApplication
クラスがライフサイクル中に投稿するすべての通知をリッスンします。 didFinishLaunching
通知はその1つであり、AppDelegate
が前述のメソッドを呼び出す原因になります。
Universal — iPhone + iPad —アプリの場合、ターゲットの情報パネルで、またはNSMainNibFile~ipad
キーとNSMainNibFile~iphone
キーをInfo.plist
に追加することにより、各プラットフォームに異なるNIBをロードするように指定できます。または、ターゲットにMainWindow~ipad.xib
NIBを追加することもできます。これは、Info.plistのNSMainNibFile
キーに基づいて、MainWindow.xib
ではなくiPadに読み込まれます。
ユニバーサルアプリの制御とカスタマイズがさらに必要な場合は、開始NIBを手動で読み込むことができます。 「ユニバーサル」プロジェクトテンプレートには、このメソッドの定型文が含まれているため、この手法の使用を開始する最も簡単な方法は、ユニバーサルプロファイルを使用して新しいiOSプロジェクトを作成することです。
上記の例では、Main NIB File
がInfo.plist
(ターゲット設定)に設定されているため、アプリケーションデリゲートが呼び出されたときにNIBが既にロードされています。通常、この設定では、MyAppDelegate
オブジェクトもNIBにアーカイブされ(いくつかのIBOutlets
を含む)、NIBのFile's Owner
はUIApplication
に設定されます。
ユニバーサルプロジェクトで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 Owner
はMYViewController
ではなく光沢のある新しいUIApplication
です。必要に応じて、MYViewController
は、アプリケーションデリゲートを使用していた可能性のあるものの多くを採用できます。これは、多くの場合、アプリのコアモデルクラスをカプセル化し、データソースとして機能し、ビューやその他のデリゲートとして機能します。 NIBのもの。
したがって、NIBにはルートUIView
が必要であり、File's Owner
(view
)のMYViewController
アウトレットに接続する必要があります。
MYViewControllerのNIBは、MYViewController.view
プロパティに最初にアクセスするまで実際にはロードされないことに注意してください。そうして初めて[MyViewController viewDidLoad]
が呼び出されます!これが発生する可能性が最も高いのは、ルートウィンドウに追加するときです。
上記のテンプレートコードでは、ルートUIWindow
はアプリデリゲートによってインスタンス化されますが、代わりにNIBに含めることができなかった理由はありません。これを行うことを選択した場合は、注意してください。その場合、NIBのウィンドウのrootViewController
をファイルの所有者に設定すると、ウィンドウがアクティブ化されたときにコントローラーのビューがウィンドウに追加されます。いずれの場合も、最初のNIBの作成には注意してください。
MYViewControllerでルートを管理する場合、アプリデリゲートは必ずしもルートUIWindow
への参照を持っている必要はありませんが、ルートウィンドウをNIBから除外し、アプリで管理する方が全体的にクリーンな場合があります。デリゲート。
それ以外(!)は、単一プラットフォームのアプローチと大差ありません。