.onDisappear: principio di funzionamento e uso in SwiftUI

Autore: IT Sectr Pubblicato: 2026-06-26 Tempo di lettura: 10 min

.onDisappear è un modificatore SwiftUI che esegue una closure quando una View viene rimossa dalla gerarchia dell'interfaccia. La chiamata avviene alla chiusura di uno schermo, al cambio di scheda, alla chiusura di una finestra modale o quando un elemento scorre fuori dalla visibilità. Secondo la Documentazione per sviluppatori Apple (2026), onDisappear non garantisce la chiamata in scenari di crash o quando l'app viene terminata dal watchdog di sistema. Per saperne di più su SwiftUI, consulta l'articolo su SwiftUI.

Punti chiave

  • .onDisappear — modificatore SwiftUI per eseguire codice alla scomparsa di una View.
  • Simmetria — onDisappear è l'opposto di onAppear e viene chiamato in ordine inverso.
  • Pulizia delle risorse — scenario principale: annullare timer, chiudere connessioni, salvare lo stato.
  • Analitica — tramite onDisappear si inviano eventi di chiusura schermo, tempo di permanenza e fine sessione.
  • Nessuna garanzia — onDisappear non viene chiamato in caso di crash dell'app.

Cos'è .onDisappear?

.onDisappear è un modificatore di View in SwiftUI che accetta una closure Void e la esegue quando la View viene rimossa dalla gerarchia. Insieme a .onAppear, forma il ciclo di vita completo di uno schermo: apparizione — lavoro — scomparsa. Apple ha introdotto onDisappear insieme a SwiftUI in iOS 13 come analogo di viewDidDisappear di UIKit.

Sintatticamente, .onDisappear è identico a onAppear: modifica qualsiasi View e collega una closure che il renderer di SwiftUI chiama quando la vista viene rimossa. A differenza di UIKit, dove viewDidDisappear si attiva solo dopo il completamento dell'animazione di transizione, onDisappear in SwiftUI può essere chiamato prima della fine dell'animazione — nel momento in cui la View viene contrassegnata per la rimozione.

Sintassi di onDisappear

Sintassi di base di onDisappear è concisa quanto quella di onAppear. Il modificatore non accetta parametri aggiuntivi — solo la closure, che viene eseguita in modo sincrono sul thread principale.

swift
struct DetailView: View {
    var body: some View {
        Text("Detail Screen")
            .onDisappear {
                print("DetailView è scomparsa dallo schermo")
            }
    }
}

Come funziona .onDisappear

Meccanismo di chiamata di onDisappear è l'opposto di onAppear: gli elementi figli ricevono onDisappear per primi, poi il genitore. Questa regola child-first garantisce che le risorse figlie vengano liberate prima che le risorse genitore vengano rilasciate. Se un elemento figlio dipende dai dati del genitore, deve poter terminare correttamente senza il contesto genitore.

SwiftUI chiama onDisappear quando la View viene rimossa dal grafo di rendering. I trigger includono: pop da NavigationStack, cambio di TabView, chiusura di modale (sheet/fullScreenCover) o una View renderizzata condizionalmente (if/switch). In List e ScrollView, onDisappear viene chiamato quando una cella scorre oltre il buffer di precaricamento.

Ordine di chiamata child-first

Ordine child-first significa che se un VStack ha tre View figlie, onDisappear viene chiamato prima per ogni figlio in ordine inverso, poi per il genitore. Questo è fondamentale per una corretta pulizia: i timer figli vengono annullati prima che il ViewModel genitore rilasci le risorse condivise.

swift
struct ParentView: View {
    var body: some View {
        VStack {
            ChildView(id: "A")
            ChildView(id: "B")
        }
        .onDisappear {
            print("Parent onDisappear — ultimo")
        }
    }
}

struct ChildView: View {
    let id: String
    var body: some View {
        Text("Child \(id)")
            .onDisappear {
                print("Child \(id) onDisappear")
            }
    }
}

Output console: Child B onDisappear, Child A onDisappear, Parent onDisappear — ultimo. L'ordine inverso rispetto a onAppear garantisce una catena di pulizia corretta.

Quando viene chiamato .onDisappear

Scenari di chiamata di onDisappear dipendono dal tipo di contenitore. In NavigationStack, onDisappear si attiva su pop-to-root, pop-back normale o chiusura dello schermo con swipe (interactivePopGestureRecognizer). In TabView, cambiare scheda chiama onDisappear per la scheda nascosta e onAppear per quella mostrata — entrambi i modificatori si attivano quasi simultaneamente.

In Sheet e fullScreenCover, onDisappear viene chiamato alla chiusura programmatica (tramite @Environment(\.dismiss)) o con un gesto di swipe verso il basso. Un dettaglio importante: se un sheet è stato aperto ma l'utente ha cambiato app, onDisappear NON viene chiamato fino alla chiusura effettiva.

ScenarioonDisappear chiamatoNota
Pop in NavigationStackSubito dopo l'animazione
Cambio scheda TabViewScheda corrente
Chiusura sheetPrima del completamento dell'animazione
Scorrimento in ListCella uscita dalla zona di precaricamento
Minimizzazione appNoNessuna garanzia di chiamata
Crash/watchdog killNoNon chiamato

Esempi di .onDisappear

Casi d'uso principali di onDisappear sono la pulizia delle risorse, il salvataggio dello stato e il tracciamento. A differenza di onAppear, le attività di onDisappear vengono eseguite all'uscita e non necessitano di controllo di duplicazione poiché la View scompare una sola volta.

Salvataggio dello stato e annullamento timer

Salvataggio dello stato in onDisappear è particolarmente utile per i moduli in cui i dati devono essere salvati quando si lascia lo schermo. I timer e le sottoscrizioni Combine vengono annullati in onDisappear per evitare perdite quando si torna allo schermo.

swift
struct FormView: View {
    @State private var draftText = ""
    @State private var timer: Timer?
    
    var body: some View {
        TextField("Enter text", text: $draftText)
            .onAppear {
                timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in
                    saveDraft()
                }
            }
            .onDisappear {
                timer?.invalidate()
                timer = nil
                saveDraft()
            }
    }
    
    private func saveDraft() {
        UserDefaults.standard.set(draftText, forKey: "draft")
    }
}

Annullamento del timer in onDisappear impedisce l'esecuzione del codice dopo che lo schermo è già stato chiuso. Senza annullamento, il timer potrebbe tentare di aggiornare @State che non appartiene più alla View corrente, causando un avviso di runtime.

Tracciamento del tempo sullo schermo

Tempo di permanenza sullo schermo è uno scenario classico di tracciamento. Registra il tempo in onAppear, calcola la differenza in onDisappear e invia un evento analitico con la durata della sessione.

swift
struct TrackedView: View {
    @State private var appearTime: Date?
    
    var body: some View {
        Text("Tracked Screen")
            .onAppear {
                appearTime = Date()
                Analytics.shared.logEvent("screen_view", params: ["screen": "TrackedView"])
            }
            .onDisappear {
                if let start = appearTime {
                    let duration = Date().timeIntervalSince(start)
                    Analytics.shared.logEvent("screen_close", params: [
                        "screen": "TrackedView",
                        "duration_ms": Int(duration * 1000)
                    ])
                }
            }
    }
}

.onDisappear vs .onAppear — differenze

La differenza chiave tra onDisappear e onAppear è l'ordine di chiamata e le garanzie di esecuzione. onAppear viene chiamato quando una View viene aggiunta alla gerarchia e può essere richiamato alla ricreazione. onDisappear viene chiamato alla rimozione ed è garantito solo alla chiusura normale, non in scenari di crash.

Secondo la WWDC 2024, Apple raccomanda di considerare onDisappear come un punto di pulizia, non come un punto di commit dei dati. I dati critici (pagamenti, registrazioni) dovrebbero essere salvati in tempo reale, non al momento della scomparsa della View, poiché onDisappear non è garantito quando l'app viene minimizzata.

Caratteristica.onAppear.onDisappear
Momento di chiamataView aggiunta alla gerarchiaView rimossa dalla gerarchia
OrdineParent-firstChild-first
GaranziaAltaNon in caso di crash
Compito principaleInizializzazionePulizia
Chiamata ripetutaAlla ricreazione della ViewUna volta per scomparsa

Raccomandazione: usa onDisappear solo per pulizia non critica e tracciamento. Per la persistenza dei dati, usa scenePhase o le notifiche applicationWillTerminate in AppDelegate.

Scenari di utilizzo tipici

Scenario 1: riproduzione stile YouTube. Sullo schermo dei dettagli del video, onDisappear salva la posizione di riproduzione in UserDefaults. Alla riapertura, onAppear ripristina la posizione da UserDefaults, creando un'esperienza di visione continua.

Scenario 2: annullare sottoscrizione Combine. Se un ViewModel utilizza publisher Combine, onDisappear annulla la sottoscrizione tramite cancellable?.cancel(). Ciò impedisce aggiornamenti dell'UI dopo aver lasciato lo schermo, particolarmente importante per liste con paginazione e query di ricerca.

Scenario 3: chiudere WebSocket. Nelle app con connessioni in tempo reale (messaggeri, feed di quotazioni), onDisappear chiude la connessione WebSocket per risparmiare batteria e dati. La riconnessione avviene in onAppear al ritorno sullo schermo.

Chiudere WebSocket in onDisappear

WebSocket è una risorsa tipica che deve essere chiusa quando si lascia lo schermo. Nell'esempio seguente, onDisappear disconnette il socket e onAppear lo riconnette, offrendo un notevole risparmio di dati per app con più schermate.

swift
struct ChatView: View {
    @StateObject private var socket = WebSocketManager()
    
    var body: some View {
        ChatListView(messages: socket.messages)
            .onAppear {
                socket.connect()
            }
            .onDisappear {
                socket.disconnect()
            }
    }
}

Importante: quando si cambiano le schede di TabView, onDisappear della scheda corrente e onAppear della scheda successiva si attivano quasi contemporaneamente. Per WebSocket, ciò può causare un ciclo di disconnessione-riconnessione che crea carico inutile. La soluzione è utilizzare un ritardo o verificare se il socket è necessario sullo schermo successivo.

Domande frequenti

.onDisappear può non essere chiamato?

Sì, .onDisappear non garantisce la chiamata in caso di crash dell'app (crash, watchdog kill), minimizzazione dell'app senza chiudere lo schermo o scenari di sistema in cui l'app viene terminata in background. Per i dati critici, usa scenePhase o applicationWillTerminate.

Come distinguere .onDisappear da .scenePhase?

.onDisappear si attiva quando una View viene rimossa dalla gerarchia — un callback locale per uno schermo specifico. .scenePhase (tramite @Environment(\.scenePhase)) si attiva quando lo stato dell'intera app cambia: active, inactive, background. Usa onAppear+onDisappear per il tracciamento del tempo sullo schermo e scenePhase per la persistenza dello stato globale.

Perché .onDisappear viene chiamato più volte di seguito?

La causa è il rapido cambio di schede o il push/pop ripetuto dello stesso schermo. SwiftUI può creare una nuova istanza di View, rimuovere quella vecchia, crearne un'altra — ogni volta chiamando onDisappear e onAppear. Verifica se stai usando .id(), .equatable() o ricreando la View nel body genitore.

.onDisappear funziona in SwiftUI su macOS?

Sì, .onDisappear è completamente supportato su macOS (10.15+) con lo stesso comportamento: viene chiamato alla chiusura della finestra, alla rimozione di un pannello di split view o alla chiusura di un modale. Su macOS, onDisappear viene chiamato anche quando si nasconde la finestra (non solo quando si chiude), il che è importante da considerare per le app macOS.

Come annullare URLSessionTask in .onDisappear?

Salva un riferimento a URLSessionTask in @State e chiama task.cancel() in onDisappear. In alternativa, usa il modificatore .task che annulla automaticamente l'operazione asincrona quando la View scompare. .task è preferito per tutte le operazioni asincrone, incluso URLSession.

Riepilogo

  • .onDisappear — modificatore gemello di onAppear per la pulizia delle risorse e il tracciamento alla scomparsa di una View.
  • Ordine child-first — le View figlie ricevono onDisappear prima del genitore per una corretta catena di pulizia.
  • Nessuna garanzia di chiamata — in caso di crash, minimizzazione o terminazione del sistema, onDisappear potrebbe non attivarsi.
  • Casi d'uso principali — annullare timer, chiudere WebSocket, salvare stato, tracciare tempo.
  • Analitica — onDisappear invia eventi screen_close con il tempo di permanenza calcolato tramite Date().timeIntervalSince.
  • Per operazioni asincrone — usa .task invece di onDisappear con Task {}, poiché .task annulla automaticamente le richieste.

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.

Discuti il progetto

Leggi anche