2011-02-10 39 views
25

Estoy tratando de averiguar la relación entre el delegado de aplicaciones, RootViewControoler y UIApplication. Esto es lo que he descifrado hasta ahora:¿Cuál es la relación entre AppDelegate, RootViewController y UIApplication?

Al iniciar la aplicación, main.m se carga.

A partir de aquí, se carga su MainWindow.xib.

En su MainWindow.xib, el propietario de su archivo es del tipo UIApplication.

Configura el delegado de su aplicación UIA en su AppDelegate.

En el código fuente de su AppDelegate, puede configurar su RootViewController para ser la primera vista que se muestra.

¿Es esto correcto? Lo que impulsa a AppDelegate a ejecutar inicialmente es

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

método?

+1

¡correcto! "DidFinishLaunchingWithOptions" es el primer método para ejecutar! –

Respuesta

44

Cuando se inicia una aplicación Objective-C, comienza ejecutando la función denominada main(). No tiene que estar en el archivo "main.m", pero así es como el asistente de Xcode configura las cosas.

Dentro de la función de asistente producido main(), no es esta línea:

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

Eso es lo que inicia la estructura de "UIKit" que conforma toda la aplicación. Dentro de UIApplicationMain, se crea un objeto de tipo UIApplication. Y parte de lo que hace la aplicación UIA cuando se inicia la aplicación es invocar el método applicationDidFinishLaunchingWithOptions en el miembro delegado de la clase UIApplication. Este delegado se configura en el archivo MainWindow.xib para que sea una instancia de su clase ProjectAppDelegate, una subclase de NSObject que se ajusta al protocolo UIApplicationDelegate.

lo que impulsa a AppDelegate inicialmente plazo es ...

Debido a que en su archivo MainWindow.xib que haya conectado (así el asistente de proyectos hizo la conexión en realidad) el propietario del archivo (que es el Objeto de UIAplicación) 'salida de delegado' al objeto UIApplicationDelegate en el archivo .xib, y la clase de UIApplicationDelegate se establece en la subclase UIApplicationDelegate de su aplicación.

Y no hay nada de mágico acerca de "MainWindow.xib", podría llamarse "Foo.xib", lo importante es que la propiedad en su archivo Info.plist llamada "Nombre de archivo de la base de datos principal" es "MainWindow". Intenta cambiar el nombre de MainWindow.xib a Foo.xib y cambiar el "nombre base del archivo de la pluma principal" en su Info.plist a "Foo" y verá que todavía funciona.

EDIT: más sobre RootController

Una vez más, no hay nada mágico en el llamado "RootController". Este es solo el nombre de la subclase UIViewController creada para usted por el nuevo asistente de proyecto de Xcode.

El asistente coloca el código en el proyecto para dos clases: ProjectAppDelegate y ProjectViewController. La clase ProjectAppDelegate contiene dos miembros de salida:

IBOutlet UIWindow *window; 
IBOutlet ProjectViewController *viewController; 

en el archivo MainWindow.xib, se colocan los casos de ambos UIWindow y ProjectViewController, y conectado a las salidas anteriores en ProjectAppDelegate.

Lo que obtiene su materia en la pantalla es el código en tu clase 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; 
} 

Una vez más, no es nada mágico en esto: el asistente de proyectos de código que añade su "raíz" punto de vista de ViewController a la creó la vista de ventana, y hace que la ventana sea visible. El controlador de vista "raíz" se creó en el archivo .xib y se conectó a la salida ProjectAppDelegate.

Es muy instructivo intentar crear una aplicación por su cuenta sin usar ninguno de los archivos del asistente. Aprenderá mucho sobre cómo funcionan los archivos .xib y cómo se relacionan con los objetos de código.

+0

Just upvoted this así pude ver que pasas de 9997 a 10k: p. No es una mala respuesta también. –

+0

w00t :) Genial, gracias – Bogatyr

1

MainWindow.xib se define en su info.plist como Main nib file base name. En su MainWindow.xib, usted define el primer controlador que desea cargar, en su caso, RootViewController.

didFinishLaunchingWithOptions: es parte del protocolo UIApplicationDelegate. Este método (en iOS4.0 +) siempre es conocido por ser el primero en ser llamado al iniciar una aplicación.

1

Dado que su AppDelegate es un delegado de UIApplication, escucha todas las notificaciones que UIApplication publicaron durante su ciclo de vida. didFinishLaunching notificación es uno de ellos y hace que su AppDelegate llame al método mencionado anteriormente.

+5

Bueno, el delegado realmente no "escucha" la notificación (como al registrarse como observador en NSNotificationCenter). En su lugar, UIApplication busca si el delegado implementa varios métodos usando 'respondsToSelector:' y los llama si existen (que deben tener exactamente el nombre predefinido, en vez de escuchar una notificación donde usted mismo puede nombrar el selector de destino). – DarkDust

15

El punto de partida de aplicaciones de iOS es siempre la función main() (gracias @bogatyr), que por lo general contiene un código similar a,

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

Los dos últimos parámetros de UIApplicationMain son importantes y especificar el nombre de la clase principal y la aplicación delegada. Si son nil, entonces se buscará Info.plist para la ventana principal xib (generalmente 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); 

No es necesario ajustar el dueño del archivo a través xib, y que se pueden especificar directamente en esta función UIApplicationMain.

principalClassName puede ser la cadena UIApplication o una subclase de UIApplication. De manera similar, delegateClassName se puede especificar directamente en este método. La clase de delegado se crea una instancia utilizando init como dicen los documentos. Supongamos que especificamos nuestra clase delegada - MyAppDelegate como una cadena,

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

En primer lugar una instancia de UIApplication se instancia, que a su vez crear la clase delegado de esta cadena utilizando NSClassFromString supongo.

Una vez que delegateObject ha sido instanciado, y la aplicación está lista, este delegateObject será informado utilizando el método de delegado, 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:...]; 

Así es como UIApplication lo manejaría mediante programación, si no se usa ninguna punta. Usar una punta en el medio no es muy diferente.

+0

No hay nada de mágico en main.m, podría llamarse foo.m, el lugar de partida es la función int main (int argc, char * argv []). – Bogatyr

+0

@Bogatyr - sí, es la función 'main()' que es el punto de partida. N No hay nada especial sobre 'main.m' como dijiste. – Anurag

1

Para universal - iPhone + iPad - aplicaciones se puede especificar que la carga diferentes ONE en cada plataforma, ya sea en el panel Información de destino o añadiendo NSMainNibFile~ipad y NSMainNibFile~iphone llaves de su Info.plist. Como alternativa, puede agregar un NIB MainWindow~ipad.xib a su destino, se cargará en el iPad en lugar de MainWindow.xib, según la clave NSMainNibFile en Info.plist.

Si necesita más control y personalización para una aplicación Universal, puede cargar el NIB de inicio manualmente. La plantilla del proyecto "Universal" tiene la plantilla estándar para este método, por lo que la forma más rápida de comenzar a usar esta técnica es crear un nuevo proyecto de iOS con el perfil Universal.

En los ejemplos anteriores, el Main NIB File se configura en Info.plist (configuración de destino) para que ya tenga un NIB cargado cuando se invoca su delegado de aplicación. Por lo general, en esta configuración, un objeto MyAppDelegate también se archivará en el NIB (con algunos IBOutlets) y el NIB File's Owner se establecerá en UIApplication.

Para que un proyecto universal pueda acomodar dos diseños alternativos, la clave principal del archivo NIB queda fuera de Info.plist. A continuación, se crea una instancia del objeto de aplicación delegado mediante programación en UIApplicationMain:

#import "MYAppDelegate.h" 

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

A continuación, compruebe su entorno y la configuración y la carga de la SEMILLA apropiado en 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]; 
} 

El nuevo paso es crear una raíz MYViewController manualmente, carga el NIB apropiado. En esta configuración, el File's Owner es su nuevo MYViewController brillante en lugar de UIApplication. Si lo desea, MYViewController puede adoptar gran parte de lo que pudo haber sido la utilización de su delegado solicitud de - que a menudo es encapsular la clase del modelo básico de la aplicación, actúan como una fuente de datos y delegado de los puntos de vista y otras cosas en el BNI.

Así que se espera que tenga una raíz UIView en el SEMILLA, y debe ser conectado a la salida de la viewFile's Owner (MYViewController).

Tenga en cuenta que la SEMILLA de MYViewController no se carga realmente hasta que la primera vez que se accede a la propiedad MYViewController.view. ¡Solo entonces se llamará al [MyViewController viewDidLoad]! El momento más probable para que esto ocurra es cuando lo agrega a la ventana raíz.

En el código de plantilla que se muestra arriba, el delegado de la aplicación crea una instancia de la raíz UIWindow, pero no hay ninguna razón para no incluirla en su NIB. Si eliges hacer esto, ten cuidado. Si configura el rootViewController de la ventana en la NIB para el propietario del archivo en ese caso, hará que la vista del controlador se agregue a la ventana cuando se active la ventana. Tenga cuidado al construir ese primer NIB en cualquier caso.

El delegado de la aplicación no necesita necesariamente tener una referencia a su raíz UIWindow si desea que MYViewController lo administre, pero puede ser más general para mantener la ventana raíz fuera de sus NIB y administrarla en el delegado de la aplicación .

Fuera de eso (!) No hay mucho diferente del enfoque de plataforma única.

Cuestiones relacionadas