Buscando comprender el ciclo de vida de iOS UIViewController

299

¿Podría explicarme la forma correcta de administrar el UIViewControllerciclo de vida?

En particular, me gustaría saber cómo utilizar Initialize, ViewDidLoad, ViewWillAppear, ViewDidAppear, ViewWillDisappear, ViewDidDisappear, ViewDidUnloady Disposemétodos en Mono táctil para una UIViewControllerclase.

Lorenzo B
fuente
¿Hay alguna información o enlace para OSX ViewController y WindowController? Por favor, comparta.
Anoop Vaidya

Respuestas:

410

IOS llama automáticamente a todos estos comandos en los momentos apropiados cuando carga / presenta / oculta el controlador de vista. Es importante tener en cuenta que estos métodos están unidos UIViewControllery no a UIViewellos mismos. No obtendrá ninguna de estas características simplemente usando a UIView.

Hay una gran documentación en el sitio de Apple aquí . Sin embargo, simplemente:

  • ViewDidLoad- Se llama cuando crea la clase y carga desde xib. Ideal para la configuración inicial y el trabajo único.

  • ViewWillAppear- Llamado justo antes de que aparezca su vista, es bueno para ocultar / mostrar campos o cualquier operación que desee que ocurra cada vez antes de que la vista sea visible. Debido a que puede estar yendo y viniendo entre las vistas, esto se llamará cada vez que su vista esté a punto de aparecer en la pantalla.

  • ViewDidAppear - Llamado después de que aparece la vista: excelente lugar para comenzar una animación o la carga de datos externos desde una API.

  • ViewWillDisappear/ DidDisappear- Misma idea que ViewWillAppear/ ViewDidAppear.

  • ViewDidUnload/ ViewDidDispose- En Objective-C, aquí es donde haces tu limpieza y liberación de cosas, pero esto se maneja automáticamente, por lo que no hay mucho que realmente necesites hacer aquí.

Jacob Knobel
fuente
86
Este texto es ligeramente engañoso, ya que ViewDidLoad no debe usarse para trabajos únicos. Se puede llamar varias veces si la vista se descarga debido a la poca memoria y luego se vuelve a cargar.
Ricky Helgesson
44
ViewDidLoad no se llama realmente cuando crea / inicializa el controlador de vista. Se llama la primera vez que realiza una vista relacionada con la vista del controlador de vista. Como agregarlo como una subvista, establecer el marco, etc. También se llama, por supuesto, cuando se carga desde una punta.
Jason Grandelli
3
ViewDidAppear: se llama después de que aparece la vista, un excelente lugar para comenzar una animación o la carga de datos externos desde una API. ¿Por qué es un buen lugar para comenzar a cargar datos? ¿Por qué no viewDidLoad?
Anton Chikin
1
¿Qué pasa con el método loadView, si se llama por primera vez cuando se carga una punta en la memoria antes de viewDidLoad o no?
iHulk
@chakrit este es un buen punto: viewDidAppear es un gran lugar para actualizar datos (si es necesario). No estoy de acuerdo con KVO, porque puede causar actualizaciones no deseadas en las vistas que nunca son vistas por un usuario.
Anton Chikin
409

ACTUALIZACIÓN: ViewDidUnload fue desaprobado en iOS 6, por lo que actualizó la respuesta en consecuencia.

El ciclo de vida de UIViewController se esquematiza aquí:

El ciclo de vida de un controlador de vista, diagramado

La ventaja de usar Xamarin Native / Mono Touch es que utiliza las API nativas, por lo que sigue el mismo ciclo de vida de ViewController que encontraría en la documentación de Apple.

Haider
fuente
17
¿Dónde van viewWillLayoutSubviews y viewDidLayoutSubviews en este diagrama de flujo?
Max_Power89
77
Este diagrama es inexacto. viewDidUnload está en desuso desde iOS6: stackoverflow.com/questions/12509102/…
occulus
2
De hecho, esto es simplemente incorrecto . Otro ejemplo de una respuesta simplemente incorrecta en SO, a medida que pasan los años. La informática es altamente no estática.
Fattie
186

Esto es para las últimas versiones de iOS (modificado con Xcode 9.3, Swift 4.1 ). A continuación se detallan todas las etapas que hacen que el ciclo de vida sea UIViewControllercompleto.

  • loadView()

  • loadViewIfNeeded()

  • viewDidLoad()

  • viewWillAppear(_ animated: Bool)

  • viewWillLayoutSubviews()

  • viewDidLayoutSubviews()

  • viewDidAppear(_ animated: Bool)

  • viewWillDisappear(_ animated: Bool)

  • viewDidDisappear(_ animated: Bool)

Déjame explicarte todas esas etapas.

1) loadView

Este evento crea / carga la vista que administra el controlador. Se puede cargar desde un archivo nib asociado o un vacío UIViewsi se encontró nulo. Esto lo convierte en un buen lugar para crear sus vistas en código mediante programación.

Aquí es donde las subclases deberían crear su jerarquía de vista personalizada si no están usando una punta. Nunca debe ser llamado directamente. Solo anule este método cuando cree vistas mediante programación y asigne la vista raíz a la viewpropiedad No llame al método super cuando anule loadView

2) loadViewIfNeeded

Si viewControlleraún no se ha configurado la vista de corriente , este método cargará la vista, pero recuerde, esto solo está disponible en iOS> = 9.0. Entonces, si es compatible con iOS <9.0, no espere que aparezca en la imagen.

Carga la vista del controlador de vista si aún no se ha configurado.

3) viewDidLoad

El viewDidLoadevento solo se llama cuando la vista se crea y se carga en la memoria, pero los límites de la vista aún no están definidos. Este es un buen lugar para inicializar los objetos que usará el controlador de vista.

Llamado después de que la vista ha sido cargada. Para los controladores de vista creados en código, esto es después de -loadView. Para los controladores de vista no archivados desde una punta, esto es después de que se establece la vista.

4) viewWillAppear

Este evento notifica viewControllercuando aparece la vista en la pantalla. En este paso, la vista tiene límites definidos pero la orientación no está establecida.

Se llama cuando la vista está a punto de hacerse visible. El valor predeterminado no hace nada.

5) viewWillLayoutSubviews

Este es el primer paso en el ciclo de vida donde se finalizan los límites. Si no está utilizando restricciones o diseño automático, probablemente desee actualizar las subvistas aquí. Esto solo está disponible en iOS> = 5.0. Entonces, si es compatible con iOS <5.0, no espere que aparezca en la imagen.

Llamado justo antes de que se invoque el método de diseño de vistas del controlador de vista. Las subclases pueden implementarse según sea necesario. El valor predeterminado es un nop.

6) viewDidLayoutSubviews

Este evento notifica al controlador de vista que las subvistas han sido configuradas. Es un buen lugar para realizar cambios en las subvistas después de que se hayan configurado. Esto solo está disponible en iOS> = 5.0. Entonces, si es compatible con iOS <5.0, no espere que aparezca en la imagen.

Se invoca justo después de invocar el diseño de vista del controlador de vista. Las subclases pueden implementarse según sea necesario. El valor predeterminado es un nop.

7) viewDidAppear

El viewDidAppearevento se dispara después de que la vista se presenta en la pantalla. Lo que lo convierte en un buen lugar para obtener datos de un servicio de fondo o una base de datos.

Se llama cuando la vista se ha transferido completamente a la pantalla. El valor predeterminado no hace nada

8) viewWillDisappear

El viewWillDisappearevento se dispara cuando se presenta la vistaviewController está a punto de desaparecer, descartar, cubrir u ocultar detrás de otro viewController. Este es un buen lugar donde puede restringir sus llamadas de red, invalidar el temporizador o liberar objetos vinculados a eso viewController.

Se llama cuando la vista se descarta, se cubre o se oculta.

9) viewDidDisappear

Este es el último paso del ciclo de vida que cualquiera puede abordar, ya que este evento se dispara justo después de la vista presentada viewController ha desaparecido, descartado, cubierto u oculto.

Llamado después de que la vista fue desestimada, cubierta u oculta. El valor predeterminado no hace nada

Ahora, según Apple, cuando implemente estos métodos, recuerde llamar a la superimplementación de ese método específico.

Si subclasifica UIViewController, debe llamar a la súper implementación de este método, incluso si no está utilizando una NIB. (Para su comodidad, el método init predeterminado lo hará por usted y especificará nulo para ambos argumentos de estos métodos). En la NIB especificada, el proxy Propietario del archivo debe tener su clase establecida en su subclase de controlador de vista, con la salida de vista conectado a la vista principal. Si invoca este método con un nombre nib nib, entonces el -loadViewmétodo de esta clase intentará cargar una NIB cuyo nombre es el mismo que la clase de su controlador de vista. Si de hecho no existe tal NIB, debe llamar -setView:antes de -viewinvocarlo o anular el -loadViewmétodo para configurar sus vistas mediante programación.

Espero que esto haya ayudado. Gracias.

ACTUALIZACIÓN : como @ThomasW señaló dentro del comentario viewWillLayoutSubviewsy viewDidLayoutSubviewstambién se le llamará en otras ocasiones cuando se cargan subvistas de la vista principal, por ejemplo, cuando se cargan las celdas de una vista de tabla o vista de colección.

ACTUALIZACIÓN : como señaló @Maria en el comentario, loadViewse actualizó la descripción de

en la terminación
fuente
66
viewWillLayoutSubviewsy viewDidLayoutSubviewstambién se llamará en otros momentos cuando se cargan subvistas de la vista principal, por ejemplo, cuando se cargan las celdas de una vista de tabla o vista de colección.
ThomasW
Hay una ligera confusión en esta respuesta: siempre se llama a loadView (), simplemente no debe anularse cuando se visualiza el controlador creado en IB.
Maria
@Maria Por favor, continúe y edite la respuesta si cree que se puede mejorar. Gracias.
onCompletion
El valor predeterminado no hace nada malo viewWillAppear viewDidAppear viewDidDisappear. Debes llamar super en algún momento.
Mick
47

iOS 10,11 (Swift 3.1, Swift 4.0)

De acuerdo con UIViewControlleren UIKitlos desarrolladores,

1. loadView ()

Aquí es donde las subclases deberían crear su jerarquía de vista personalizada si no están usando una punta . Nunca debe ser llamado directamente.

2. loadViewIfNeeded ()

Carga la vista del controlador de vista si aún no se ha configurado.

3. viewDidLoad ()

Llamado después de que la vista ha sido cargada. Para los controladores de vista creados en código, esto es después de -loadView. Para los controladores de vista no archivados desde una punta, esto es después de que se establece la vista.

4. viewWillAppear (_ animado: Bool)

Se llama cuando la vista está a punto de hacerse visible. El valor predeterminado no hace nada

5. viewWillLayoutSubviews ()

Llamado justo antes de que se invoque el método de diseño de vistas del controlador de vista. Las subclases pueden implementarse según sea necesario. El valor predeterminado no hace nada.

6. viewDidLayoutSubviews ()

Se invoca justo después de invocar el diseño de vista del controlador de vista. Las subclases pueden implementarse según sea necesario. El valor predeterminado no hace nada.

7. viewDidAppear (_ animado: Bool)

Se llama cuando la vista se ha transferido completamente a la pantalla. El valor predeterminado no hace nada

8. viewWillDisappear (_ animado: Bool)

Se llama cuando la vista se descarta, se cubre o se oculta. El valor predeterminado no hace nada

9. viewDidDisappear (_ animado: Bool )

Llamado después de que la vista fue desestimada, cubierta u oculta. El valor predeterminado no hace nada

10. viewWillTransition (a tamaño: CGSize, con coordinador: UIViewControllerTransitionCoordinator)

Se llama cuando la vista está en transición.

11. willMove (toParentViewController parent: UIViewController?)

12. didMove (toParentViewController parent: UIViewController?)

Estos dos métodos son públicos para que se invoquen las subclases de contenedores al realizar la transición entre controladores secundarios. Si se anulan, las anulaciones deben asegurarse de llamar al super.

El argumento padre en ambos métodos es nulo cuando un niño está siendo eliminado de su padre; de lo contrario, es igual al nuevo controlador de vista principal.

13. didReceiveMemoryWarning ()

Se llama cuando la aplicación principal recibe una advertencia de memoria. En iOS 6.0 ya no borrará la vista de forma predeterminada.

Rajamohan S
fuente
2
Realmente supone que stackoverflow no eliminará todas las respuestas incorrectas e incompletas de todo este hilo. Su respuesta parece completa en lo que respecta a las llamadas a métodos, por lo que voy a asumir que la suya es correcta y trabajaré con eso.
Logicsaurus Rex
¿Qué es un nibcomo se menciona a continuación loadView?
Petrus Theron
2
@LogicsaurusRex Estoy de acuerdo. De la misma manera que SO marca las preguntas como duplicadas o protegidas, creo que debería poder marcar las respuestas como obsoletas u obsoletas
rmp251
El punto 5 anterior está mal. viewWillLayoutSubviews()se llama antes de que el objeto de vista de ViewController invoque su layoutSubviews()método
williamukoh
28

A partir de iOS 6 y posteriores. El nuevo diagrama es el siguiente:

ingrese la descripción de la imagen aquí

Saad
fuente
1
Llame a esa vista "A". Considere una segunda vista "B" que aparece mientras "A" desaparece. ¿Es "B.viewWillAppear" antes o después de "A.viewDidDisappear"? ¿Y hay alguna situación en la que cambie el orden de esos dos?
ToolmakerSteve
Parece que la nueva vista (B) willApear se llamará antes de que desaparezca. Para la segunda pregunta Necesito algo de tiempo para investigarlo.
Saad
21

Concentrémonos en los métodos, que son responsables del ciclo de vida de UIViewController :

  • Creación:

    - (void)init

    - (void)initWithNibName:

  • Ver creación:

    - (BOOL)isViewLoaded

    - (void)loadView

    - (void)viewDidLoad

    - (UIView *)initWithFrame:(CGRect)frame

    - (UIView *)initWithCoder:(NSCoder *)coder

  • Manejo del cambio de estado de vista:

    - (void)viewDidLoad

    - (void)viewWillAppear:(BOOL)animated

    - (void)viewDidAppear:(BOOL)animated

    - (void)viewWillDisappear:(BOOL)animated

    - (void)viewDidDisappear:(BOOL)animated

    - (void)viewDidUnload

  • Manejo de advertencia de memoria:

    - (void)didReceiveMemoryWarning

  • Desasignación

    - (void)viewDidUnload

    - (void)dealloc

Diagrama del ciclo de vida del controlador UIViewController

Para obtener más información, consulte la Referencia de clase UIViewController .

Alexey Pelekh
fuente
19

Los métodos viewWillLayoutSubviewsy viewDidLayoutSubviewsno se mencionan en los diagramas, pero estos se llaman entre viewWillAppeary viewDidAppear. Se les puede llamar varias veces.

gjgjgj
fuente
También se llamarán en otros momentos cuando se cargan subvistas de la vista principal, por ejemplo, cuando se cargan las celdas de una vista de tabla o vista de colección.
ThomasW
16

La respuesta de Haider es correcta para pre-iOS 6. Sin embargo, a partir de iOS 6 nunca se llama a viewDidUnload y viewWillUnload. Los documentos indican: "Las vistas ya no se purgan en condiciones de poca memoria, por lo que este método nunca se llama".

Matt Becker
fuente
Intenté poner un punto de interrupción en ViewWillDisappear, ViewDidDisappear, Dispose. Pero ninguno de ellos estaba siendo invocado cuando navegué con el método PresentViewController (). Cuál podría ser la razón ?
Sreeraj
1
El enlace no funciona ... Entonces, ¿qué hace el sistema operativo con poca memoria?
Hijo
Los guarda en el disco?
Ian Warburton
16

Aquí hay mucha información obsoleta e incompleta. Solo para iOS 6 y versiones posteriores :

  1. loadView[una]
  2. viewDidLoad[una]
  3. viewWillAppear
  4. viewWillLayoutSubviews es la primera vez que se finalizan los límites
  5. viewDidLayoutSubviews
  6. viewDidAppear
  7. * viewWillLayoutSubviews[si]
  8. * viewDidLayoutSubviews[si]

Notas al pie:

(a) - Si cierra manualmente su vista durante didReceiveMemoryWarning, loadViewy viewDidLoadse le volverá a llamar. Es decir, de forma predeterminada loadViewy viewDidLoadsolo se llama una vez por instancia de controlador de vista.

(b) Puede llamarse un 0 o más veces adicionales .

bobics
fuente
1
viewWillLayoutSubviewsy viewDidLayoutSubviewstambién se llamará en otros momentos cuando se cargan subvistas de la vista principal, por ejemplo, cuando se cargan las celdas de una vista de tabla o vista de colección.
ThomasW
0

Según el documento de Apple - Comience a desarrollar aplicaciones de iOS (Swift) - Trabaje con controladores de vista - Comprenda el ciclo de vida del controlador de vista

viewDidLoad(): Se llama cuando la vista de contenido del controlador de vista (la parte superior de su jerarquía de vista) se crea y carga desde un guión gráfico. ... Use este método para realizar cualquier configuración adicional requerida por su controlador de vista.

viewWillAppear(): Se llama justo antes de que se agregue la vista de contenido del controlador de vista a la jerarquía de vistas de la aplicación. Use este método para activar cualquier operación que deba ocurrir antes de que la vista de contenido se presente en pantalla

viewDidAppear(): Se llama justo después de que se haya agregado la vista de contenido del controlador de vista a la jerarquía de vistas de la aplicación. Use este método para desencadenar cualquier operación que deba ocurrir tan pronto como la vista se presente en pantalla, como obtener datos o mostrar una animación.

viewWillDisappear(): Se llama justo antes de que la vista de contenido del controlador de vista se elimine de la jerarquía de vistas de la aplicación. Use este método para realizar tareas de limpieza como confirmar cambios o renunciar al estado del primer respondedor.

viewDidDisappear(): Se llama justo después de que la vista de contenido del controlador de vista se haya eliminado de la jerarquía de vistas de la aplicación. Use este método para realizar actividades adicionales de desmontaje.

Fred
fuente