.onDisappear: principiul de funcționare și aplicarea în SwiftUI

Autor: IT Sectr Publicat: 2026-06-26 Timp de citire: 10 min

.onDisappear — un modificator SwiftUI care execută o închidere la ștergerea unui View din ierarhia interfeței. Apelul are loc la închiderea ecranului, schimbarea filei, dismiss-ul unei ferestre modale sau derularea unui element în afara zonei vizibile. Conform Apple Developer Documentation (2026), onDisappear nu garantează apelul în scenarii de terminare accidentală sau la distrugerea aplicației de către system-watchdog. Citiți mai multe despre SwiftUI în materialul despre SwiftUI.

Principalele

  • .onDisappear — modificator SwiftUI pentru executarea codului la dispariția unui View.
  • Simetrie — onDisappear este perechea lui onAppear și este apelat în ordine inversă.
  • Curățarea resurselor — scenariul principal: anularea timerelor, închiderea conexiunilor, salvarea stării.
  • Analitică — prin onDisappear se trimit evenimente screen close, dwell time, session end.
  • Lipsa garanției — onDisappear nu este apelat la terminarea accidentală a aplicației.

Ce este .onDisappear?

.onDisappear — un modificator View în SwiftUI care acceptă o închidere Void și o execută la ștergerea View-ului din ierarhie. Împreună cu .onAppear formează ciclul complet de viață al ecranului: apariție — lucru — dispariție. Apple a introdus onDisappear odată cu lansarea SwiftUI în iOS 13 ca analog al viewDidDisappear din UIKit.

Sintactic .onDisappear este identic cu onAppear: modifică orice View și atașează o închidere care este apelată de componenta SwiftUI la ștergerea vizualizării. Spre deosebire de UIKit, unde viewDidDisappear se declanșează doar după finalizarea animației de tranziție, onDisappear în SwiftUI poate fi apelat înainte de finalizarea animației — în momentul în care View este marcat pentru ștergere.

Sintaxa onDisappear

Sintaxa de bază a onDisappear este la fel de concisă ca cea a onAppear. Modificatorul nu acceptă parametri suplimentari — doar închiderea care se execută sincron în thread-ul principal.

swift
struct DetailView: View {
    var body: some View {
        Text("Ecranul de Detalii")
            .onDisappear {
                print("DetailView a dispărut de pe ecran")
            }
    }
}

Cum funcționează .onDisappear

Mecanismul de apel al onDisappear este opus onAppear: mai întâi elementele copil primesc onDisappear, apoi părintele. Această regulă child-first garantează că resursele elementelor copil sunt eliberate înaintea resurselor părintelui. Dacă un element copil depinde de datele părintelui, trebuie să se poată finaliza corect fără contextul părintelui.

SwiftUI apelează onDisappear în momentul în care View este exclus din graful de randare. Declanșatorul poate fi: pop din NavigationStack, schimbarea TabView, dismiss-ul unei ferestre modale (sheet/fullScreenCover), schimbarea unui View afișat condiționat (if/switch). În List și ScrollView onDisappear este apelat la derularea celulei în afara buffer-ului de prefetch.

Ordinea de apel child-first

Ordinea child-first înseamnă că dacă într-un VStack sunt trei View-uri copil, onDisappear va fi apelat mai întâi pentru fiecare copil în ordine inversă, apoi pentru părinte. Acest lucru este critic pentru curățarea corectă: timer-ele copil sunt anulate înainte ca ViewModel-ul părintelui să elibereze resursele partajate.

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

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

Ieșirea în consolă: Child B onDisappear, Child A onDisappear, Parent onDisappear — ultimul. Ordinea inversă față de onAppear garantează un lanț corect de eliberare.

Când este apelat .onDisappear

Scenariile de apel ale onDisappear depind de tipul containerului. În NavigationStack onDisappear se declanșează la pop-to-root, pop-back obișnuit sau eliminarea ecranului prin gest de glisare (interactivePopGestureRecognizer). În TabView schimbarea filei declanșează onDisappear pentru cea ascunsă și onAppear pentru cea afișată — ambele modificatoare se declanșează aproape simultan.

În Sheet și fullScreenCover onDisappear este apelat la dismiss programatic (prin @Environment(\.dismiss)) sau prin gest de glisare în jos. O caracteristică importantă: dacă sheet-ul a fost deschis, dar utilizatorul a comutat aplicația, onDisappear NU este apelat până la închiderea efectivă.

ScenariuonDisappear este apelatNotă
Pop în NavigationStackDaImediat după animație
Schimbarea filei TabViewDaFila curentă
Dismiss sheetDaÎnainte de finalizarea animației
Derulare în ListDaCelula a ieșit din zona de prefetch
Minimizarea aplicațieiNuNu există garanție de apel
Crash/watchdog killNuNu este apelat

Exemple .onDisappear

Scenariile principale ale onDisappear — curățarea resurselor, salvarea stării și urmărirea. Spre deosebire de onAppear, sarcinile onDisappear se execută la ieșire și nu necesită verificarea duplicării, deoarece View dispare o singură dată.

Salvarea stării și anularea timerelor

Salvarea stării în onDisappear este utilă în special pentru formulare, unde datele trebuie salvate la părăsirea ecranului. Timer-ele și abonamentele Combine sunt anulate în onDisappear pentru a evita scurgerile de memorie la revenirea pe ecran.

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")
    }
}

Anularea timer-ului în onDisappear previne executarea codului după ce ecranul a fost deja închis. Fără anulare, timer-ul poate încerca să actualizeze un @State care nu mai aparține View-ului curent, generând un runtime warning.

Urmărirea timpului pe ecran

Durata de staționare pe ecran — un scenariu clasic de urmărire. Înregistrăm timpul în onAppear, calculăm diferența în onDisappear și trimitem un eveniment analitic cu durata sesiunii.

swift
struct TrackedView: View {
    @State private var appearTime: Date?
    
    var body: some View {
        Text("Ecran Urmărit")
            .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 — diferențe

Diferența cheie dintre onDisappear și onAppear — ordinea de apel și garanțiile de declanșare. onAppear este apelat la adăugarea View-ului în ierarhie și are proprietatea de re-apelare la recreare. onDisappear este apelat la ștergere și garantează funcționarea doar la închiderea normală, dar nu în scenarii accidentale.

Conform WWDC 2024, Apple recomandă să considerați onDisappear ca punct de curățare, nu ca punct de salvare a datelor. Datele critic de importante (plăți, înregistrări) trebuie salvate în timp real, nu în momentul dispariției View-ului, deoarece onDisappear nu garantează apelul la minimizarea aplicației.

Caracteristică.onAppear.onDisappear
Momentul apelăriiAdăugarea View în ierarhieȘtergerea View din ierarhie
OrdineaParent-firstChild-first
GaranțiaRidicatăNu la terminări accidentale
Sarcina principalăInițializareCurățare
Re-apelareLa recrearea ViewO singură dată la dispariție

Recomandare: utilizați onDisappear doar pentru curățare necritică și urmărire. Pentru salvarea datelor utilizați scenePhase sau notificările applicationWillTerminate în AppDelegate.

Scenarii tipice de utilizare

Scenariul 1: încărcare asemănătoare YouTube. Pe ecranul de detalii video onDisappear salvează poziția de redare în UserDefaults. La redeschidere, onAppear restabilește poziția din UserDefaults, oferind efect de vizionare continuă.

Scenariul 2: anularea abonamentului Combine. Dacă ViewModel utilizează publisher-i Combine, onDisappear anulează abonamentul prin cancellable?.cancel(). Aceasta previne actualizarea UI după părăsirea ecranului, ceea ce este important în special pentru liste cu paginare și interogări de căutare.

Scenariul 3: închiderea WebSocket. În aplicațiile cu conexiuni în timp real (mesagerie, fluxuri de cotații) onDisappear închide conexiunea WebSocket pentru economisirea bateriei și a traficului. Redeschiderea are loc în onAppear la revenirea pe ecran.

Închiderea WebSocket în onDisappear

WebSocket — o resursă tipică care trebuie închisă la părăsirea ecranului. În exemplul de mai jos onDisappear deconectează socket-ul, iar onAppear îl reconectează, oferind o economie semnificativă de trafic pentru aplicațiile cu mai multe ecrane.

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

Important: la comutarea între filele TabView, onDisappear al filei curente și onAppear al filei următoare se declanșează aproape simultan. Pentru WebSocket aceasta poate duce la un ciclu disconnect-connect care creează sarcină suplimentară. Soluția — utilizarea unei întârzieri sau verificarea dacă socket-ul este necesar pe ecranul următor.

Întrebări frecvente

Poate .onDisappear să nu fie apelat?

Da, .onDisappear nu garantează apelul la terminarea accidentală a aplicației (crash, watchdog kill), minimizarea aplicației fără închiderea ecranului sau scenariul de sistem în care aplicația este distrusă în fundal. Pentru date critic importante utilizați scenePhase sau applicationWillTerminate.

Cum deosebim .onDisappear de .scenePhase?

.onDisappear se declanșează la ștergerea View-ului din ierarhie — un callback local pentru un ecran specific. .scenePhase (prin @Environment(\.scenePhase)) se declanșează la schimbarea stării întregii aplicații: active, inactive, background. Pentru urmărirea timpului pe ecran utilizați onAppear+onDisappear, pentru salvarea stării globale — scenePhase.

De ce .onDisappear este apelat de mai multe ori la rând?

Cauza — comutarea rapidă între file sau push/pop repetat al aceluiași ecran. SwiftUI poate crea o nouă instanță View, șterge-o pe cea veche, crea din nou — de fiecare dată declanșând onDisappear și onAppear. Verificați dacă nu utilizați .id(), .equatable() sau dacă nu recreați View-ul în body-ul părintelui.

Funcționează .onDisappear în SwiftUI pe macOS?

Da, .onDisappear este complet suportat pe macOS (10.15+) cu același comportament: apelat la închiderea ferestrei, ștergerea panoului split view sau dismiss-ul ferestrei modale. Pe macOS onDisappear este apelat și la ascunderea ferestrei (hide), nu doar la închidere, ceea ce este important pentru aplicațiile macOS.

Cum anulăm URLSessionTask în .onDisappear?

Salvați referința la URLSessionTask în @State și apelați task.cancel() în onDisappear. Alternativ, utilizați modificatorul .task care anulează automat operația async la dispariția View-ului. .task este preferat pentru toate operațiile async, inclusiv URLSession.

Rezumat

  • .onDisappear — modificator pereche la onAppear pentru curățarea resurselor și urmărire la dispariția View-ului.
  • Ordinea child-first — View-urile copil primesc onDisappear mai devreme decât părintele pentru un lanț corect de eliberare.
  • Nu există garanție de apel — la crash, minimizare sau terminare sistemică onDisappear poate să nu funcționeze.
  • Scenariile principale — anularea timerelor, închiderea WebSocket, salvarea stării, urmărirea duratei.
  • Analitică — onDisappear trimite evenimente screen_close cu calcularea dwell time prin Date().timeIntervalSince.
  • Pentru operații async — utilizați .task în loc de onDisappear cu Task {}, deoarece .task anulează automat cererile.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și