¿Cómo funciona View Controller Containment en iOS 5?

108

En la WWDC 2011 Sesión 102, Apple introdujo Vista Controlador de contención, que es la capacidad de crear la vista personalizada contenedores controlador, de forma análoga a UITabBarController, UINavigationControllery similares.

Vi los ejemplos varias veces. Hay una serie de métodos asociados con este patrón, pero fue un poco difícil descifrarlos exactamente. Voy a publicar aquí lo que creo que está sucediendo y veré si la comunidad confirma o desautoriza mis sospechas.

Escenario 1: Pasar de no tener padre a un nuevo controlador de vista padre

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

¿Tienen que aparecer las dos primeras líneas en el orden indicado o pueden invertirse?

Escenario 2: pasar de un controlador de vista principal a ningún controlador de vista principal

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

¿También es necesario llamar [vc didMoveToParentViewController:nil]? Los ejemplos de la Sesión 102 no hicieron esto en este escenario, pero no sé si fue una omisión o no.

Escenario 3: pasar de un controlador de vista principal a otro

Es probable que esto ocurra de la siguiente manera, porque la lógica en cada controlador de vista principal estará encapsulada.

// In the old parent
[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];

// In the new parent
[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view];
[vc didMoveToParentViewController:self];

Preguntas

Mi pregunta principal es la siguiente: ¿Así es como debería funcionar la contención del controlador de vista, en general? ¿Son correctas las mecánicas dadas arriba?

¿Es necesario llamar willMoveToParentViewControllerantes de llamar addChildViewController? Este me parece el orden lógico, pero ¿es estrictamente necesario?

¿Es necesario llamar didMoveToParentViewController:nildespués de llamar removeFromParentViewController?

Gregory Higley
fuente

Respuestas:

72

Los UIViewControllerdocumentos son bastante claros sobre cuándo y cuándo no llamar a willMove/ didMovemétodos. Consulte la documentación "Implementación de un controlador de vista de contenedor" .

Los documentos dicen que si no anula addChildViewController, no tiene que llamar al willMoveToParentViewController:método. Sin embargo, debe llamar al didMoveToParentViewController:método después de que se complete la transición. "Del mismo modo, es responsabilidad del controlador de vista de contenedor llamar al willMoveToParentViewController:método antes de llamar al removeFromParentViewControllermétodo. El removeFromParentViewControllermétodo llama al didMoveToParentViewController:método del controlador de vista secundario".

Además, hay un ejemplo elaborado aquí y un código de muestra aquí .

Buena suerte

timthetoolman
fuente
17
Ya veo, entonces addChildViewControllerdebería equilibrarse con didMoveToParentViewControllery willMoveToParentViewControllerdebería equilibrarse con removeFromParentViewController. Esto es exactamente lo que estaba buscando. No estoy seguro de cómo me lo perdí en los documentos.
Gregory Higley
Por qué no? ¿Por qué no tiene que llamar a willMoveToParentViewController pero tiene que llamar a didMoveToParentViewController?
user4951
Porque eso es lo que dicen los doctores. Apple, obviamente, siente que no necesitamos saberlo.
7
La razón es por el bien de la animación: digamos que está creando su propio controlador de navegación. Al comienzo de una animación de deslizamiento, se debe llamar a 'willMove' y, al final de la animación, se debe llamar a 'didMove'. Ahora, cuando llama a 'addChild' al comienzo de la animación, automáticamente llama a 'willMove' por usted. Pero no puede saber cuándo finaliza la animación (si hay una), por lo que debe llamar a 'didMove' manualmente al final de la animación (o inmediatamente sin animación).
Chris
2
Y en cuanto a una animación de 'deslizamiento hacia afuera', por ejemplo, el niño está siendo eliminado, debe llamar a 'willMove' manualmente al comienzo de la animación, porque uikit de otra manera no sabría cuándo llamar al VC de su hijo 'viewWillDisappear'. Y al final de la animación, cuando llama a removeFromParentViewController, puede llamar a 'didMove' automáticamente por usted.
Chris
23

Esta parte no es correcta:

[vc willMoveToParentViewController:self];
[self addChildViewController:vc];
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

Según los documentos:

Cuando su contenedor personalizado llama al método addChildViewController:, automáticamente llama al método willMoveToParentViewController: del controlador de vista para agregarlo como hijo antes de agregarlo.

Entonces no necesitas la [vc willMoveToParentViewController:self]llamada. Se hace automáticamente cuando llama [self addChildViewController:vc]. Aquí está el ejemplo de código nuevamente:

[self addChildViewController:vc];
// [vc willMoveToParentViewController:self] called automatically
[self.view addSubview:vc.view]; // or something like this.
[vc didMoveToParentViewController:self];

Para eliminar los controladores de vista:

El método removeFromParentViewController llama automáticamente al método didMoveToParentViewController: del controlador de vista secundario después de eliminar al niño.

Presumiblemente esta llamada lo es [oldVC didMoveToParentViewController:nil].

[vc willMoveToParentViewController:nil];
[vc.view removeFromSuperview];
[vc removeFromParentViewController];
// [vc didMoveToParentViewController:nil] called automatically
rey nevan
fuente
parece que si se hace de otra manera, incluso si parece funcionar, presentViewController no está configurado en PresentViewController.
Adrian
Los documentos dicen llamar didMoveToParentViewController " inmediatamente después de llamar al método addChildViewController:", no especifica cuándo realmente agrega la subvista secundaria. Me pregunto si todo el mundo se habrá equivocado. ¿Hay algún ejemplo en algunos documentos de Apple con el que podamos comparar esto?
Robert
Nota: se hace necesario llamar willMoveToParentViewControllerantes addChildViewControllersi el artículo que usted está en movimiento es una clase personalizada con anulado addChildViewController(a menos que su anulación llama internamente)
bunkerdive