.onAppear: principio de funcionamiento, ciclo de vida y ejemplos en SwiftUI

Autor: IT Sectr Publicado: 2026-06-26 Tiempo de lectura: 10 min

.onAppear es un modificador de SwiftUI que ejecuta un closure cuando se añade una View a la jerarquía de la interfaz. La llamada ocurre una vez por aparición de la instancia en pantalla y sirve como punto principal para cargar datos, iniciar animaciones y enviar eventos de analítica. Según Apple Developer Documentation (2026), onAppear garantiza la ejecución antes del primer renderizado, pero no garantiza la llamada en cada visualización repetida si la View permanece en memoria. Más información sobre SwiftUI en el artículo sobre SwiftUI.

Puntos clave

  • .onAppear es un modificador de SwiftUI para ejecutar código cuando una View aparece en pantalla.
  • Ejecución única — onAppear se llama una vez por ciclo de vida de View si permanece en memoria.
  • Carga de datos — el caso de uso principal de onAppear: fetch de API, lectura de Core Data o UserDefaults.
  • Animaciones — onAppear inicia animaciones de entrada: opacity, scale, offset con retardo.
  • Analítica — los eventos screen view, impression, page open se envían mediante onAppear.

¿Qué es .onAppear?

.onAppear es un modificador de View en SwiftUI que toma un closure Void y lo ejecuta cuando la View se vuelve visible en pantalla. Este modificador forma parte del sistema de ciclo de vida de componentes SwiftUI junto con .onDisappear y .task. Apple presentó onAppear con el lanzamiento de SwiftUI en iOS 13 y watchOS 6 como reemplazo de viewDidLoad de UIKit.

Sintácticamente, .onAppear modifica cualquier View y devuelve la misma View con una acción adjunta. El compositor de SwiftUI llama al closure una vez cuando la vista se añade a la jerarquía y pasa la etapa de renderizado. Si una View se elimina y luego se vuelve a añadir (por ejemplo, al hacer scroll en una lista), onAppear se llama de nuevo — este comportamiento a menudo se convierte en fuente de errores inesperados.

Sintaxis de onAppear

La sintaxis básica del modificador es minimalista: onAppear sin parámetros. SwiftUI no permite pasar prioridad o animación — el closure se ejecuta sincrónicamente en el hilo principal inmediatamente después del renderizado.

swift
struct ContentView: View {
    var body: some View {
        Text("Hello, SwiftUI!")
            .onAppear {
                print("View appeared on screen")
            }
    }
}

Limitaciones: onAppear no soporta async/await directamente. Para operaciones asíncronas dentro del closure se necesita Task {} o una función async/await separada llamada mediante Task.detached. Esto hace que onAppear sea menos conveniente para peticiones de red en comparación con el modificador .task.

Cómo funciona .onAppear en el ciclo de vida de View

.onAppear se integra en el pipeline de renderizado de SwiftUI en la etapa layout+render. Cuando SwiftUI calcula el cuerpo de la View y detecta un cambio en la jerarquía, ejecuta los callbacks onAppear para todas las vistas recién añadidas. El orden de llamada sigue la anidación: onAppear del padre primero, luego los elementos hijo.

Una característica importante de SwiftUI es que onAppear no está vinculado a la aparición física en pantalla. El modificador se llama cuando una View se añade a la jerarquía, independientemente de si es visible para el usuario (por ejemplo, fuera de pantalla en un ScrollView). Esto diferencia SwiftUI de UIKit, donde viewWillAppear solo se ejecuta en la aparición real.

Orden de llamada de onAppear

El orden de llamada sigue la regla padre-primero: VStack o NavigationView recibe onAppear primero, luego cada elemento hijo en orden. Esto es crítico para la inicialización de recursos compartidos: si los elementos hijo dependen de datos cargados por el padre, deben verificar la disponibilidad mediante Optional.

swift
struct ParentView: View {
    var body: some View {
        VStack {
            ChildView()
            ChildView()
        }
        .onAppear {
            print("Parent onAppear — first")
        }
    }
}

struct ChildView: View {
    var body: some View {
        Text("Child")
            .onAppear {
                print("Child onAppear")
            }
    }
}

La salida en consola será: Parent onAppear — primero, luego Child onAppear dos veces en orden. Este comportamiento está garantizado por Apple y es estable en todas las versiones de SwiftUI (iOS 13–18).

Cuándo se llama .onAppear

.onAppear tiene varios escenarios de llamada que dependen del contenedor y la navegación. En NavigationStack, onAppear se ejecuta en cada push de un nuevo controlador y en pop — para el controlador raíz. En TabView, cambiar de pestaña llama a onAppear para la pestaña mostrada y onDisappear para la oculta.

En List y ScrollView, onAppear se llama para las celdas que han entrado en el área visible o están en el búfer de pre-renderizado. iOS 18 introdujo un mecanismo de prefetch que puede llamar a onAppear para celdas 2–3 pantallas antes del scroll — esto acelera la percepción pero puede provocar peticiones de red innecesarias.

Comportamiento de llamada en NavigationStack

NavigationStack (iOS 16+) gestiona la pila de pantallas de manera diferente a NavigationView. Al hacer push de una nueva pantalla, onAppear se ejecuta solo en la nueva pantalla, mientras que la actual no recibe onDisappear hasta la eliminación real. En pop ocurre el proceso inverso: onDisappear en la pantalla que se abandona, onAppear en la que regresa.

EscenarioonAppearonDisappear
PushNueva pantallaNo (la pantalla permanece en la pila)
PopPantalla que regresaPantalla que se abandona
Cambio de pestañaNueva pestañaPestaña anterior
Cerrar sheetPantalla padreSheet abierto

Ejemplos de uso de .onAppear

Las aplicaciones prácticas de onAppear abarcan tres categorías principales: carga de datos, inicio de animaciones y envío de analítica. Cada escenario requiere considerar las características del ciclo de vida de SwiftUI para evitar llamadas duplicadas y fugas de memoria.

Carga de datos desde API

La carga de datos es el caso de uso más común de onAppear. Dentro del closure se crea un Task para la llamada async, y el resultado se almacena en @State o @StateObject. Es importante verificar si los datos ya se han cargado usando un flag isLoading o comprobación de nil.

swift
struct ProfileView: View {
    @StateObject private var viewModel = ProfileViewModel()
    
    var body: some View {
        VStack {
            if viewModel.isLoading {
                ProgressView()
            } else {
                Text(viewModel.userName)
            }
        }
        .onAppear {
            guard viewModel.userName == nil else { return }
            Task {
                await viewModel.loadProfile()
            }
        }
    }
}

Protección contra re-fetch es una práctica crítica. Si SwiftUI recrea la View (por ejemplo, al rotar la pantalla), onAppear se ejecutará de nuevo sin protección. Una alternativa es el modificador .task, que cancela automáticamente la petición anterior.

Inicio de animación de entrada

La animación de entrada usa onAppear para cambiar variables de estado que activan la animación mediante withAnimation o el modificador animation. Patrón típico: estado inicial (opacity 0, offset 100), transición a estado final (opacity 1, offset 0) al aparecer.

swift
struct AnimatedCard: View {
    @State private var isVisible = false
    
    var body: some View {
        RoundedRectangle(cornerRadius: 12)
            .fill(Color.blue)
            .opacity(isVisible ? 1 : 0)
            .offset(y: isVisible ? 0 : 50)
            .animation(.spring(), value: isVisible)
            .onAppear {
                withAnimation(.spring().delay(0.3)) {
                    isVisible = true
                }
            }
    }
}

El retardo de 0.3 segundos crea un efecto de aparición secuencial si hay varias tarjetas en pantalla. Para una lista de elementos animados, usa el índice del elemento como multiplicador de retardo.

.onAppear vs .task — diferencias

.task es un modificador de SwiftUI añadido en iOS 15 que resuelve el problema de las operaciones asíncronas en onAppear. A diferencia de onAppear, .task acepta un closure async, gestiona automáticamente su ciclo de vida y lo cancela cuando la View desaparece. Mientras onAppear se ejecuta sincrónicamente, .task lanza una operación asíncrona y permite a SwiftUI cancelarla en onDisappear.

La principal diferencia es la gestión de cancelación. Cuando .task crea una operación async, SwiftUI guarda una referencia al Task y llama automáticamente a cancel() cuando la View se elimina de la jerarquía. onAppear con Task {} dentro no cancela la operación en ejecución — continúa incluso después de que la View haya desaparecido, lo que puede causar condiciones de carrera o escritura en una instancia desasignada.

Característica.onAppear.task
Versión iOSiOS 13+iOS 15+
Soporte asyncSolo mediante Task {}Async/await nativo
Auto-cancelaciónNoAl desaparecer la View
Re-llamadaEn cada apariciónUna vez por defecto
Código síncronoSolo async

Elección del modificador: para acciones síncronas (animaciones, analítica, logging) usa onAppear. Para carga de datos asíncrona (API, Core Data, sistema de archivos) prefiere .task — es más seguro y limpio.

Errores comunes con .onAppear

Error 1: llamadas múltiples por recreación de View. Cuando SwiftUI recrea el cuerpo de la View (cambio de estado, rotación de pantalla), onAppear puede llamarse de nuevo. Solución — añadir un flag de carga o usar .equatable() para evitar redibujados innecesarios. Según SwiftLee (2025), el 40% de los bugs de SwiftUI en producción están relacionados con llamadas repetidas de onAppear.

Error 2: fuga de memoria por referencia fuerte. Si el closure de onAppear captura self sin una referencia débil, se crea un ciclo de retención con la View. SwiftUI no garantiza la anulación de objetos capturados cuando la View desaparece. Usa capture list [weak self] para ViewModel o servicios.

Error 3: ejecución en hilo secundario. onAppear se ejecuta en el hilo principal — esto es correcto para operaciones de UI. Pero si inicias un Task dentro de onAppear, asegúrate de que la actualización de @State ocurra mediante MainActor.run. Swift 5.9 y superior vuelven automáticamente a MainActor, pero es mejor especificar @MainActor explícitamente.

Cómo evitar llamadas repetidas

El patrón con un flag de carga es la forma más fiable de protegerse contra la duplicación. Almacena el flag en @State o @StateObject y restablécelo solo en actualización manual. Una alternativa es usar .task en lugar de onAppear: .task no se reinicia al redibujar por defecto si la operación async ya se está ejecutando.

swift
struct SafeView: View {
    @State private var hasAppeared = false
    @State private var items: [Item] = []
    
    var body: some View {
        List(items, id: \.id) { item in
            Text(item.name)
        }
        .onAppear {
            guard !hasAppeared else { return }
            hasAppeared = true
            Task {
                items = await DataService.shared.fetchItems()
            }
        }
    }
}

Preguntas frecuentes

¿En qué se diferencia .onAppear de viewDidLoad en UIKit?

viewDidLoad se llama una vez durante la vida de UIViewController, independientemente de la visibilidad. .onAppear se llama cada vez que se añade una View a la jerarquía — si una View se elimina y se vuelve a añadir, onAppear se ejecuta de nuevo. En NavigationView, viewDidLoad se llama durante la inicialización, mientras que onAppear se llama en cada visualización de pantalla.

¿Se puede llamar una función async dentro de .onAppear?

Sí, mediante un wrapper Task { await asyncFunction() }. Sin embargo, para operaciones async es preferible usar .task, que gestiona automáticamente la cancelación y no requiere crear un Task manualmente. .task también garantiza la cancelación cuando la View desaparece, evitando fugas.

¿Por qué .onAppear se llama varias veces?

La razón es la recreación del cuerpo de la View debido a cambios en @State, @Published o la configuración del ancestro. SwiftUI puede redibujar una View en respuesta a cambios en cualquier propiedad observable. Además, LazyVStack y List llaman a onAppear para las celdas que se acercan al área visible, y de nuevo al hacer scroll hacia arriba.

¿Funciona .onAppear en watchOS y tvOS?

Sí, .onAppear está disponible en todas las plataformas SwiftUI: iOS 13+, watchOS 6+, tvOS 13+, macOS 10.15+. El comportamiento es idéntico: el modificador se llama cuando se añade una View a la jerarquía. En watchOS, onAppear se ejecuta al activar la aplicación desde el estado de espera, lo que debe tenerse en cuenta en el diseño.

¿Cómo pasar parámetros a .onAppear?

.onAppear no acepta parámetros — solo un closure Void. Para pasar parámetros, usa un closure que capture variables externas. Un enfoque alternativo es crear un modificador onAppear personalizado con parámetros mediante ViewModifier o un equivalente de .onChange.

Resumen

  • .onAppear es un modificador de SwiftUI para ejecutar código cuando se añade una View a la jerarquía de la interfaz.
  • Llamada única — onAppear se llama una vez por instancia de View si permanece en memoria.
  • Orden padre-primero — las View padre reciben onAppear antes que las hijas.
  • Casos de uso principales — carga de datos, inicio de animaciones, envío de analítica.
  • .task es preferible para operaciones async por su auto-cancelación al desaparecer la View.
  • Protección — obligatoria para evitar llamadas repetidas al redibujar la View.

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.

Discutir el proyecto

Lea también