.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 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.
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.
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.
.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.
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.
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).
.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.
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.
| Escenario | onAppear | onDisappear |
|---|---|---|
| Push | Nueva pantalla | No (la pantalla permanece en la pila) |
| Pop | Pantalla que regresa | Pantalla que se abandona |
| Cambio de pestaña | Nueva pestaña | Pestaña anterior |
| Cerrar sheet | Pantalla padre | Sheet abierto |
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.
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.
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.
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.
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.
.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 iOS | iOS 13+ | iOS 15+ |
| Soporte async | Solo mediante Task {} | Async/await nativo |
| Auto-cancelación | No | Al desaparecer la View |
| Re-llamada | En cada aparición | Una vez por defecto |
| Código síncrono | Sí | Solo 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.
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.
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.
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
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.
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.
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.
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.
.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
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