.onAppear è un modificatore SwiftUI che esegue una closure quando una View viene aggiunta alla gerarchia dell’interfaccia. La chiamata avviene una volta per apparizione dell’istanza sullo schermo e funge da punto principale per caricare dati, avviare animazioni e inviare eventi di analisi. Secondo la Apple Developer Documentation (2026), onAppear garantisce l’esecuzione prima del primo rendering, ma non garantisce la chiamata a ogni visualizzazione ripetuta se la View rimane in memoria. Ulteriori informazioni su SwiftUI nell’articolo su SwiftUI.
Punti chiave
.onAppear è un modificatore di View in SwiftUI che accetta una closure Void e la esegue quando la View diventa visibile sullo schermo. Questo modificatore fa parte del sistema del ciclo di vita dei componenti SwiftUI insieme a .onDisappear e .task. Apple ha introdotto onAppear con il rilascio di SwiftUI in iOS 13 e watchOS 6 come sostituto di viewDidLoad di UIKit.
Sintatticamente, .onAppear modifica qualsiasi View e restituisce la stessa View con un’azione allegata. Il compositore SwiftUI chiama la closure passata una volta quando la view viene aggiunta alla gerarchia e supera la fase di rendering. Se una View viene rimossa e poi aggiunta di nuovo (ad esempio, scorrendo in un elenco), onAppear viene chiamato di nuovo — questo comportamento diventa spesso fonte di bug imprevisti.
La sintassi di base del modificatore è minimalista: onAppear senza parametri. SwiftUI non offre alcun modo per passare priorità o animazione — la closure viene eseguita in modo sincrono sul thread principale immediatamente dopo il rendering.
struct ContentView: View {
var body: some View {
Text("Hello, SwiftUI!")
.onAppear {
print("View appeared on screen")
}
}
}
Limitazioni: onAppear non supporta async/await direttamente. Per operazioni asincrone all’interno della closure, è necessario Task {} o una funzione async/await separata chiamata tramite Task.detached. Ciò rende onAppear meno conveniente per le richieste di rete rispetto al modificatore .task.
.onAppear è incorporato nella pipeline di rendering di SwiftUI nella fase layout+render. Quando SwiftUI calcola il corpo della View e rileva un cambiamento nella gerarchia, attiva i callback onAppear per tutte le view appena aggiunte. L’ordine di chiamata segue l’annidamento: onAppear del genitore prima, poi gli elementi figli.
Una caratteristica importante di SwiftUI è che onAppear non è legato all’apparizione fisica sullo schermo. Il modificatore viene chiamato quando una View viene aggiunta alla gerarchia, indipendentemente dal fatto che sia visibile all’utente (ad esempio, fuori schermo in una ScrollView). Questo distingue SwiftUI da UIKit, dove viewWillAppear viene attivato solo all’apparizione effettiva.
L’ordine di chiamata segue la regola genitore-primo: VStack o NavigationView riceve onAppear per primo, poi ogni elemento figlio in ordine. Ciò è fondamentale per l’inizializzazione delle risorse condivise: se gli elementi figli dipendono dai dati caricati dal genitore, devono verificare la disponibilità tramite 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")
}
}
}
L’output della console sarà: Parent onAppear — primo, poi Child onAppear due volte in ordine. Questo comportamento è garantito da Apple e stabile in tutte le versioni di SwiftUI (iOS 13–18).
.onAppear ha diversi scenari di chiamata che dipendono dal contenitore e dalla navigazione. In NavigationStack, onAppear viene attivato a ogni push di un nuovo controller e al pop — per il controller radice. In TabView, il cambio di scheda chiama onAppear per la scheda visualizzata e onDisappear per quella nascosta.
In List e ScrollView, onAppear viene chiamato per le celle che sono entrate nell’area visibile o si trovano nel buffer di pre-rendering. iOS 18 ha introdotto un meccanismo di prefetch che può chiamare onAppear per le celle 2–3 schermi prima dello scorrimento — questo accelera la percezione ma può provocare richieste di rete non necessarie.
NavigationStack (iOS 16+) gestisce lo stack di schermi in modo diverso da NavigationView. Quando si fa push di un nuovo schermo, onAppear viene attivato solo sul nuovo schermo, mentre quello corrente non riceve onDisappear fino alla rimozione effettiva. Al pop, avviene il processo inverso: onDisappear sullo schermo che si abbandona, onAppear su quello che ritorna.
| Scenario | onAppear | onDisappear |
|---|---|---|
| Push | Nuovo schermo | No (lo schermo rimane nello stack) |
| Pop | Schermo di ritorno | Schermo abbandonato |
| Cambio scheda | Nuova scheda | Vecchia scheda |
| Chiusura sheet | Schermo genitore | Sheet aperto |
Le applicazioni pratiche di onAppear coprono tre categorie principali: caricamento dati, avvio animazioni e invio di analisi. Ogni scenario richiede la considerazione delle caratteristiche del ciclo di vita di SwiftUI per evitare chiamate duplicate e perdite di memoria.
Il caricamento dati è il caso d’uso più comune di onAppear. All’interno della closure, viene creato un Task per la chiamata async e il risultato viene memorizzato in @State o @StateObject. È importante verificare se i dati sono già stati caricati utilizzando un flag isLoading o un controllo 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()
}
}
}
}
La protezione contro il re-fetch è una pratica critica. Se SwiftUI ricrea la View (ad esempio, alla rotazione dello schermo), onAppear si attiverà di nuovo senza protezione. Un’alternativa è il modificatore .task, che annulla automaticamente la richiesta precedente.
L’animazione di ingresso utilizza onAppear per modificare le variabili di stato che attivano l’animazione tramite withAnimation o il modificatore animation. Schema tipico: stato iniziale (opacity 0, offset 100), transizione allo stato finale (opacity 1, offset 0) all’apparizione.
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
}
}
}
}
Il ritardo di 0,3 secondi crea un effetto di apparizione sequenziale se ci sono più carte sullo schermo. Per un elenco di elementi animati, utilizzare l’indice dell’elemento come moltiplicatore di ritardo.
.task è un modificatore SwiftUI aggiunto in iOS 15 che risolve il problema delle operazioni asincrone in onAppear. A differenza di onAppear, .task accetta una closure async, gestisce automaticamente il suo ciclo di vita e la annulla quando la View scompare. Mentre onAppear viene eseguito in modo sincrono, .task avvia un’operazione asincrona e permette a SwiftUI di annullarla in onDisappear.
La differenza principale è la gestione dell’annullamento. Quando .task crea un’operazione async, SwiftUI salva un riferimento al Task e chiama automaticamente cancel() quando la View viene rimossa dalla gerarchia. onAppear con Task {} all’interno non annulla l’operazione in esecuzione — continua anche dopo che la View è scomparsa, il che può causare condizioni di competizione o scritture in un’istanza deallocata.
| Caratteristica | .onAppear | .task |
|---|---|---|
| Versione iOS | iOS 13+ | iOS 15+ |
| Supporto async | Solo tramite Task {} | Async/await nativo |
| Auto-annullamento | No | Alla scomparsa della View |
| Richiamata | A ogni apparizione | Singola per default |
| Codice sincrono | Sì | Solo async |
Scelta del modificatore: per azioni sincrone (animazioni, analisi, logging) usa onAppear. Per il caricamento asincrono di dati (API, Core Data, file system) preferisci .task — è più sicuro e pulito.
Errore 1: chiamate multiple dovute alla ricreazione della View. Quando SwiftUI ricrea il corpo della View (cambio di stato, rotazione dello schermo), onAppear può essere chiamato di nuovo. Soluzione — aggiungi un flag di caricamento o usa .equatable() per prevenire ridisegni non necessari. Secondo SwiftLee (2025), il 40% dei bug di SwiftUI in produzione sono correlati a chiamate ripetute di onAppear.
Errore 2: perdita di memoria per riferimento forte. Se la closure di onAppear cattura self senza un riferimento debole, crea un ciclo di ritenzione con la View. SwiftUI non garantisce l’azzeramento degli oggetti catturati quando la View scompare. Usa la capture list [weak self] per ViewModel o servizi.
Errore 3: esecuzione su thread in background. onAppear viene eseguito sul thread principale — questo è corretto per le operazioni UI. Ma se avvii un Task all’interno di onAppear, assicurati che l’aggiornamento di @State avvenga tramite MainActor.run. Swift 5.9 e superiori tornano automaticamente a MainActor, ma è meglio specificare @MainActor esplicitamente.
Il pattern con un flag di caricamento è il modo più affidabile per proteggersi dalla duplicazione. Memorizza il flag in @State o @StateObject e reimpostalo solo all’aggiornamento manuale. Un’alternativa è usare .task invece di onAppear: .task non si riavvia al ridisegno per default se l’operazione async è già in esecuzione.
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()
}
}
}
}
Domande frequenti
viewDidLoad viene chiamato una volta durante la vita di UIViewController, indipendentemente dalla visibilità. .onAppear viene chiamato ogni volta che una View viene aggiunta alla gerarchia — se una View viene rimossa e aggiunta di nuovo, onAppear si attiva nuovamente. In NavigationView, viewDidLoad viene chiamato durante l’inizializzazione, mentre onAppear viene chiamato a ogni visualizzazione dello schermo.
Sì, tramite un wrapper Task { await asyncFunction() }. Tuttavia, per le operazioni async è preferibile .task, che gestisce automaticamente l’annullamento e non richiede la creazione manuale di un Task. .task garantisce anche l’annullamento alla scomparsa della View, prevenendo perdite.
La causa è la ricreazione del corpo della View a causa di modifiche a @State, @Published o alla configurazione di un antenato. SwiftUI può ridisegnare una View in risposta a modifiche in qualsiasi proprietà osservabile. Inoltre, LazyVStack e List chiamano onAppear per le celle che si avvicinano all’area visibile, e di nuovo quando si scorre verso l’alto.
Sì, .onAppear è disponibile su tutte le piattaforme SwiftUI: iOS 13+, watchOS 6+, tvOS 13+, macOS 10.15+. Il comportamento è identico: il modificatore viene chiamato quando una View viene aggiunta alla gerarchia. Su watchOS, onAppear si attiva quando l’app viene attivata dallo stato di standby, il che deve essere considerato nella progettazione.
.onAppear non accetta parametri — solo una closure Void. Per passare parametri, usa una closure che cattura variabili esterne. Un approccio alternativo è creare un modificatore onAppear personalizzato con parametri tramite ViewModifier o un equivalente di .onChange.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche