ViewController Lifecycle es la secuencia de métodos que UIKit llama automáticamente al gestionar pantallas en iOS. Según la Documentación de Apple, cada UIViewController pasa por un conjunto predecible de estados: desde la creación de la View hasta su aparición y desaparición. Comprender el orden y el propósito de estos métodos es una condición necesaria para el funcionamiento estable de una app iOS.
Puntos clave
ViewController Lifecycle es un conjunto de métodos que UIViewController recibe de UIKit a lo largo de su existencia. Cada pantalla en una app iOS pasa secuencialmente por las etapas de creación, carga de View, aparición en pantalla, desaparición y liberación de memoria. UIKit llama automáticamente los métodos correspondientes en cada etapa, y el desarrollador los sobrescribe para agregar su lógica.
La arquitectura de UIViewController es fundamental para UIKit y sigue siendo relevante incluso en la era de SwiftUI — muchos proyectos siguen usando el enfoque clásico o una arquitectura híbrida. Comprender el Lifecycle permite predecir en qué momento las subviews están disponibles, cuándo es seguro modificar el layout y qué operaciones realizar al aparecer o desaparecer la pantalla.
Cada método del ciclo de vida tiene un propósito específico: algunos se llaman una sola vez durante toda la vida del controlador, otros — en cada aparición o desaparición. Mezclar la lógica entre métodos conduce a errores difíciles de encontrar: fugas de memoria, actualizaciones incorrectas de datos y solicitudes de red innecesarias.
Seis métodos forman el ciclo de vida completo de UIViewController. El orden de llamada es fijo y no depende del método de navegación — push, present o unwind segue siguen el mismo programa.
loadView es el primer método del ciclo, llamado cuando la View del controlador aún no existe. Si usas Storyboard, UIKit carga automáticamente la View desde el archivo xib. Al crear la interfaz mediante programación, sobrescribes este método asignando la View raíz manualmente. En la mayoría de los proyectos, loadView no se toca — el trabajo se hace en viewDidLoad.
Sobrescribir loadView solo es necesario en casos específicos: cuando toda la interfaz se crea en código sin Storyboard, o cuando la View raíz debe ser de una clase no estándar. Apple recomienda no llamar a super.loadView al sobrescribir — asumes toda la responsabilidad de crear la View.
override func loadView() {
view = UIView()
view.backgroundColor = .white
}
viewDidLoad es el método más utilizado del ciclo. Se llama una vez después de que la View se carga en memoria pero aún no se muestra en pantalla. Aquí se configuran las subviews, se llenan las tablas con datos, se registran las celdas y se suscriben notificaciones que duran toda la vida del controlador.
Una característica importante: viewDidLoad no se vuelve a llamar cuando la pantalla se muestra nuevamente. Si necesitas actualizar datos cada vez que aparece la pantalla — usa viewWillAppear. Coloca solo operaciones únicas en viewDidLoad que sean necesarias para la configuración básica.
viewWillAppear se llama cada vez justo antes de que la View se vuelva visible para el usuario. Este método recibe un parámetro animated que indica si la aparición es animada. Aquí se actualizan datos, se recargan tablas, se configura el NavigationBar y se ocultan o muestran elementos según el estado de la aplicación.
Usa viewWillAppear para la sincronización de estado entre pantallas: si el usuario pudo haber cambiado datos en la pantalla anterior, este método es el lugar adecuado para actualizar la interfaz. Cada llamada a viewWillAppear precede a la aparición de la pantalla, incluso al regresar de un controlador hijo.
viewDidAppear notifica que la View ha aparecido completamente en pantalla y todas las animaciones de transición han finalizado. En este punto, la pantalla está lista para la interacción — el usuario ve la interfaz completa y puede interactuar con ella. Este método es adecuado para iniciar animaciones que deben comenzar después de la aparición, iniciar temporizadores y rastrear impresiones de análisis.
A diferencia de viewWillAppear, viewDidAppear garantiza que la pantalla no solo es visible sino que también se ha renderizado por completo. Si inicias una animación en viewWillAppear, es posible que se omitan algunos fotogramas porque UIKit aún no ha completado la transición. Para animaciones suaves, usa viewDidAppear.
viewWillDisappear se llama antes de que la View desaparezca de la pantalla — al hacer la transición a otro controlador, cerrar una ventana modal o suspender la app. Este es el lugar adecuado para guardar el estado, cancelar la suscripción a notificaciones, detener procesos activos y liberar recursos que no se necesitan cuando la pantalla no es visible.
Es importante recordar: viewWillDisappear no garantiza que la View finalmente desaparezca — el gesto puede cancelarse. Por lo tanto, guarda los datos críticos también en viewDidDisappear, que se llama solo después de la desaparición real.
viewDidDisappear completa el ciclo de aparición y desaparición. Se llama después de que la View ya está oculta de la pantalla. En este método, se detienen finalmente las animaciones, se eliminan los objetos temporales y se confirma el guardado de datos iniciado en viewWillDisappear.
Este método también precede al deinit del controlador — si tu UIViewController se destruye, viewDidDisappear será el último método del Lifecycle antes de que se llame a deinit. Úsalo para la limpieza final que debe ocurrir antes de que el objeto sea destruido.
La secuencia de llamadas depende de cómo aparece la pantalla: por primera vez, al regresar o cuando se presenta modalmente. Consideremos tres escenarios principales desde la perspectiva de UIKit.
Cuando una pantalla aparece por primera vez, UIKit recorre el ciclo completo de creación: se llama a loadView, luego a viewDidLoad, después de lo cual comienza la animación de aparición. Durante la animación, se llama a viewWillAppear, y al finalizar — a viewDidAppear. Este es el único escenario donde todos los métodos desde loadView hasta viewDidAppear se activan secuencialmente.
override func viewDidLoad() {
super.viewDidLoad()
print("viewDidLoad — View cargada en memoria")
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("viewWillAppear — Próximo a aparecer")
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("viewDidAppear — Pantalla completamente visible")
}
Cuando el usuario regresa a una pantalla anterior, UIKit no vuelve a llamar a viewDidLoad — la View ya está cargada en memoria. En su lugar, solo se llaman viewWillAppear y viewDidAppear en la pantalla de retorno, y en la actual — viewWillDisappear y viewDidDisappear. loadView y viewDidLoad se omiten ya que la pantalla ya existe en la pila de navegación.
La presentación modal sigue las mismas reglas: el nuevo controlador pasa por el ciclo completo en la primera aparición, mientras que el actual recibe viewWillDisappear y viewDidDisappear. Al hacer dismiss, el orden se invierte: el controlador que regresa obtiene viewWillAppear y viewDidAppear nuevamente, mientras que el descartado recibe los métodos finales. Este comportamiento es uniforme para todos los tipos de transición en UIKit.
Veamos cuatro escenarios clave donde la comprensión del Lifecycle impacta directamente en la calidad del código y la experiencia del usuario. Para cada escenario, proporcionamos un ejemplo con recomendaciones.
viewDidLoad es el lugar para la configuración inicial que no depende de la visibilidad de la pantalla. Aquí se configura el collectionView, se registran archivos nib para las celdas, se crean fuentes de datos y layouts. Si estás cargando datos de la red, en viewDidLoad es mejor solo iniciar la solicitud y actualizar la UI en viewWillAppear cuando la pantalla esté lista para mostrarse.
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(
MyCell.self,
forCellReuseIdentifier: MyCell.identifier
)
viewModel.loadInitialData()
}
Usa viewWillAppear para la sincronización de datos cada vez que aparece la pantalla. Por ejemplo, si el usuario pudo haber cambiado la configuración en la pantalla anterior, aquí se actualizan los valores mostrados, se recarga la tabla y se ajusta el estado del NavigationBar. Esto garantiza que la pantalla siempre muestre datos actualizados en cualquier escenario de navegación.
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
tableView.reloadData()
navigationController?.setNavigationBarHidden(false, animated: animated)
}
viewDidAppear es ideal para iniciar animaciones que deben comenzar después de que el usuario haya visto la pantalla. Aquí también se envían eventos de análisis: visualización de pantalla, inicio de onboarding o reproducción de video. Iniciar animaciones antes de que la transición esté completa provoca una interfaz entrecortada — UIKit no tiene tiempo suficiente para preparar una cantidad adecuada de fotogramas.
En viewWillDisappear, se guardan borradores, se detienen temporizadores y se cancela la suscripción a NotificationCenter. Este es el último momento en que la pantalla aún es visible y accesible para operaciones que requieren contexto del usuario. Para datos críticos, usa adicionalmente viewDidDisappear como protección contra gestos cancelados.
El uso incorrecto de los métodos del ciclo de vida es una de las fuentes más frecuentes de errores en apps iOS. Veamos los principales errores que cometen los desarrolladores en diferentes etapas del trabajo con UIViewController.
El primer error — crear subviews en init o loadView al usar Storyboard. Si estás usando Interface Builder, no sobrescribas loadView innecesariamente. Crear una View en loadView cuando existe un storyboard resulta en ignorar el archivo xib y obtener una pantalla vacía.
El segundo error — suscribirse a notificaciones de teclado en viewDidLoad sin cancelar la suscripción. Si te suscribiste a UIResponder.keyboardWillShowNotification pero no cancelaste la suscripción al ocultar la pantalla, el bloque se seguirá llamando incluso después del deinit del controlador — esto es una fuga de memoria con posible bloqueo de la app.
El tercer error — temporizadores y solicitudes de red iniciados antes de que aparezca la pantalla. Cargar imágenes o realizar animaciones cuando la View aún no es visible es un desperdicio de recursos. Mueve las actualizaciones visuales a viewWillAppear o viewDidAppear.
El cuarto error — guardar datos solo en viewWillDisappear. Con un gesto de pop interactivo, el usuario puede comenzar un deslizamiento y cancelarlo — el método se llamó pero la pantalla no desapareció. Duplica el guardado crítico en viewDidDisappear o en el manejador applicationDidEnterBackground.
Preguntas frecuentes
Una vez — después de cargar la View en memoria. Cuando la pantalla aparece nuevamente, viewDidLoad no se llama. Si necesitas recrear la View, el controlador debe ser destruido y creado de nuevo.
UIKit requiere llamar a super.viewDidLoad para que el ciclo de vida funcione correctamente. Sin ello, pueden ocurrir problemas con las actualizaciones de layout y el manejo de transiciones. Siempre llama a super como primera acción dentro del método.
No se recomienda. Si el controlador se inicializa desde Storyboard, UIKit carga automáticamente la View desde el xib. Sobrescribir loadView cancela este proceso y tu storyboard será ignorado.
Suscríbete en viewDidLoad o viewWillAppear, y cancela la suscripción en viewWillDisappear o viewDidDisappear, usando una referencia débil a self para evitar fugas de memoria con closures.
El forzar el cierre mata el proceso abruptamente — UIKit no tiene tiempo para llamar a los métodos del Lifecycle. Para guardar datos, usa la notificación UIApplication.willTerminateNotification en AppDelegate.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también