Implementación correcta de LoadView

Los documentos de Apple no dicen cuál es la implementación correcta para loadView.

Descubrí que si implementas loadView así:

- (void)loadView { self.view = [[UIView alloc] init]; } 

… entonces obtienes un comportamiento diferente que si no lo implementas en absoluto. En particular, en un proyecto de 20 líneas, he encontrado que viewWillAppear se invoca con un marco de tamaño cero para self.view, a less que use la versión pnetworkingeterminada de Apple de loadView.

Mirando en Google, hay muchos "tutoriales" que proporcionan implementaciones loadView obviamente incorrectas, por ejemplo, forzar el tamaño (320,480) porque el autor del tutorial "encontró que funciona si lo hago".

Me gustaría saber cuál debería ser la implementación correcta.

Nota: en mi ejemplo anterior, lo agrego a la jerarquía de vista dentro de AppDelegate así:

 [self.window addSubview:(UIViewController*).view]; 

Creo que en presencia de un UINavigationController o UITabBarController, Apple hace algo de magia adicional que, como efecto secundario, hace que una implementación loadView de una línea funcione correctamente. ¡Pero quiero escribirlo correctamente, para que siempre funcione!

NB: He intentado configurar la máscara de autorrealización en la vista raíz, pero no cambia lo que sucede:

 - (void)loadView { self.view = [[UIView alloc] init]; self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; } 

La implementación por defecto de -loadView crea la vista o carga NIB . Hasta donde sé, no hay forma de saber el tamaño final de la vista en el momento de la creación en -loadView . Por lo tanto, el tamaño de vista pnetworkingeterminado se establece en [[UIScreen mainScreen] bounds] . Esto se debe a que puede ser difícil trabajar con vistas de cero frameworks en -viewDidLoad y otros methods.

Su implementación de una línea puede verse así:

 - (void)loadView { self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; } 

No necesita configurar la máscara de autorrealización, porque no sabe en qué context se mostrará la vista. La persona que llama es responsable de establecer el marco correcto, máscara de autorización y attributes externos similares (los llamo así).

Imagine esto en un método UINavigationController :

 // we are pushing new VC, view is accessed for the first time pushedVC.view.frame = CGRectMake(...); 

Está configurando el marco correcto, pero su -loadView se llama justo antes de eso -setFrame: . Entonces durante -viewDidLoad tienes un marco temporal distinto de cero, solo para poder configurar subvistas y autorrealización interna. Después de esto, el marco correcto está configurado en usted y en la vista -viewWillAppear: tiene el marco final.

Primero, no hay implementación 'pnetworkingeterminada' de loadView … ese método está específicamente allí para que usted anule. Estoy de acuerdo en que los documentos de Apple pueden ser un poco confusos. Pero loadView se loadView por defecto siempre que se accede a la vista del controller de navigation y no existe ninguna vista (por ejemplo: UIView *view = viewController.view ). También se puede llamar manualmente. Pero en ninguna situación loadView tendrá las dimensiones correctas … es decir, de hecho, imposible. Se llama a loadView para que el controller de vista primario obtenga la vista en primer lugar para que pueda dimensionarlo adecuadamente. Luego, una vez que obtiene la vista, llama a viewDidLoad . Esta es la única ruta de código que pueden usar porque las vistas se pueden cargar desde el método loadView o la punta y deben proporcionar un lugar para la configuration adicional cuando las vistas se cargan desde una punta. Finalmente, el controller padre cambiará el tamaño de la vista y llamará a viewWillAppear solo cuando la vista realmente aparezca. Por ejemplo, si presiona un controller en un navController que está fuera de la pantalla, no llamará a viewWillAppear hasta que el propio navController esté en la pantalla. Esto se hace porque no tiene sentido ejecutar ese código hasta que el controller esté realmente visible. Esta es también la razón por la que solo puede get la dimensión correcta en el método viewWillAppear .

Ahora, notó que si agrega un controller a un controller estándar, no sucede nada de esto. Esto se debe a que los controlleres de vista realmente no tienen la intención de contener otros controlleres de vista por decir. Ahora en iOS 5, admiten explícitamente el uso de Controladores de vista de contenedor … que es esencialmente un controller de vista que está diseñado para contener otros controlleres de vista. Añadieron algunos methods de "conveniencia" en iOS 5 para ayudar con esto, pero no es estrictamente necesario. Lo esencial de todo esto es: si desea agregar un controller de vista a otro, deberá configurar manualmente todas las llamadas apropiadas para el controller de vista secundaria (todos los methods de carga, events de rotation, advertencia de memory, etc.). En otras palabras, debe crear su propio controller de vista de contenedor. Sin embargo, cuando lo haga, tenga en count lo que dije antes sobre la ruta del código. Es importante que llame a los methods del controller secundario en el mismo order que Apple hace o cosas no funcionarán bien.

Aquí hay algunos enlaces a información: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIViewController_Class/Reference/Reference.html -Scroll down to: Implementación de un controller de vista de contenedor

También aquí para ver el ciclo de vida del controller, que lo ayudará a determinar qué llamadas deben realizarse en qué order: http://developer.apple.com/library/ios/#featunetworkingarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html# // apple_ref / doc / uid / TP40007457-CH10-SW1

Recomiendo leer toda la Guía de Progtwigción del Controlador de Vista … puedes ver mucha información desde allí: http://developer.apple.com/library/ios/#featunetworkingarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html#/ / apple_ref / doc / uid / TP40007457-CH1-SW1