.onDisappear: princip fungování a aplikace v SwiftUI

Autor: IT Sectr Publikováno: 2026-06-26 Doba čtení: 10 min

.onDisappear — modifikátor SwiftUI, který provádí uzavření při odstranění View z hierarchie rozhraní. Volání nastává při zavření obrazovky, přepnutí karty, dismiss modálního okna nebo scrollování prvku mimo viditelnou oblast. Podle Apple Developer Documentation (2026), onDisappear negarantuje volání ve scénářích nouzového ukončení nebo při zničení aplikace system-watchdogem. Více o SwiftUI si přečtěte v materiálu o SwiftUI.

Hlavní body

  • .onDisappear — modifikátor SwiftUI pro provádění kódu při zmizení View.
  • Symetrie — onDisappear je párový k onAppear a volá se v obráceném pořadí.
  • Čištění zdrojů — hlavní scénář: zrušení časovačů, zavření připojení, uložení stavu.
  • Analytika — přes onDisappear se odesílají události screen close, dwell time, session end.
  • Chybějící záruka — onDisappear se nevolá při nouzovém ukončení aplikace.

Co je .onDisappear?

.onDisappear — modifikátor View ve SwiftUI, který přijímá uzavření Void a provádí ho při odstranění View z hierarchie. Spolu s .onAppear tvoří úplný životní cyklus obrazovky: objevení — práce — zmizení. Apple představil onDisappear spolu s vydáním SwiftUI v iOS 13 jako analogii viewDidDisappear z UIKit.

Syntaxicky je .onDisappear identický s onAppear: modifikuje libovolný View a připojuje uzavření, které je voláno komponentou SwiftUI při odstranění zobrazení. Na rozdíl od UIKit, kde viewDidDisappear se aktivuje až po dokončení přechodové animace, onDisappear ve SwiftUI může být volán před dokončením animace — v okamžiku, kdy je View označen k odstranění.

Syntaxe onDisappear

Základní syntaxe onDisappear je stejně stručná jako onAppear. Modifikátor nepřijímá žádné další parametry — pouze uzavření, které se provádí synchronně v hlavním vlákně.

swift
struct DetailView: View {
    var body: some View {
        Text("Obrazovka detailů")
            .onDisappear {
                print("DetailView zmizel z obrazovky")
            }
    }
}

Jak funguje .onDisappear

Mechanismus volání onDisappear je opačný než onAppear: nejprve podřízené elementy obdrží onDisappear, poté rodič. Toto pravidlo child-first zaručuje, že zdroje podřízených elementů jsou uvolněny před uvolněním zdrojů rodiče. Pokud podřízený element závisí na datech rodiče, musí být schopen se správně ukončit bez kontextu rodiče.

SwiftUI volá onDisappear v okamžiku, kdy je View vyloučen z vykreslovacího grafu. Spouštěčem může být: pop z NavigationStack, přepnutí TabView, dismiss modálního okna (sheet/fullScreenCover), změna podmíněně zobrazeného View (if/switch). V List a ScrollView se onDisappear volá při scrollování buňky mimo prefetch buffer.

Pořadí volání child-first

Pořadí child-first znamená, že pokud jsou ve VStack tři podřízené View, onDisappear bude volán nejprve pro každé dítě v obráceném pořadí, poté pro rodiče. To je kritické pro správné čištění: podřízené časovače jsou zrušeny dříve, než rodičovský ViewModel uvolní sdílené zdroje.

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

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

Výstup do konzole: Child B onDisappear, Child A onDisappear, Parent onDisappear — poslední. Obrácené pořadí ve srovnání s onAppear zaručuje správný řetězec uvolňování.

Kdy se volá .onDisappear

Scénáře volání onDisappear závisí na typu kontejneru. V NavigationStack se onDisappear spouští při pop-to-root, běžném pop-back nebo odstranění obrazovky gestem přetažení (interactivePopGestureRecognizer). V TabView přepnutí karty spouští onDisappear pro skrytou a onAppear pro zobrazenou — oba modifikátory se spouští téměř současně.

V Sheet a fullScreenCover se onDisappear volá při programovém dismiss (přes @Environment(\.dismiss)) nebo gestu přetažení dolů. Důležitá vlastnost: pokud byl sheet otevřen, ale uživatel přepnul aplikaci, onDisappear se NEVOLá do skutečného zavření.

ScénářonDisappear se voláPoznámka
Pop v NavigationStackAnoIhned po animaci
Přepnutí karty TabViewAnoAktuální karta
Dismiss sheetAnoPřed dokončením animace
Scroll v ListAnoBuňka opustila prefetch zónu
Minimalizace aplikaceNeŽádná záruka volání
Crash/watchdog killNeNevolá se

Příklady .onDisappear

Hlavní scénáře onDisappear — čištění zdrojů, ukládání stavu a sledování. Na rozdíl od onAppear se úlohy onDisappear provádějí při odchodu a nevyžadují kontrolu duplicity, protože View mizí jednorázově.

Ukládání stavu a rušení časovačů

Ukládání stavu v onDisappear je užitečné zejména pro formuláře, kde data musí být uložena při opuštění obrazovky. Časovače a Combine odběry se ruší v onDisappear, aby se předešlo únikům paměti při návratu na obrazovku.

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

Zrušení časovače v onDisappear zabraňuje provádění kódu po uzavření obrazovky. Bez zrušení může časovač zkusit aktualizovat @State, který již nepatří aktuálnímu View, což způsobí runtime varování.

Sledování času na obrazovce

Délka pobytu na obrazovce — klasický scénář sledování. Zaznamenáme čas v onAppear, vypočítáme rozdíl v onDisappear a odešleme analytickou událost s délkou relace.

swift
struct TrackedView: View {
    @State private var appearTime: Date?
    
    var body: some View {
        Text("Sledovaná obrazovka")
            .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 — rozdíly

Klíčový rozdíl onDisappear od onAppear — pořadí volání a záruky aktivace. onAppear se volá při přidání View do hierarchie a má vlastnost opakovaného volání při regeneraci. onDisappear se volá při odstranění a zaručeně funguje pouze při normálním zavření, ale ne v nouzových scénářích.

Podle WWDC 2024 Apple doporučuje považovat onDisappear za bod čištění, nikoli za bod ukládání dat. Kriticky důležitá data (platby, registrace) by měla být ukládána v reálném čase, ne v okamžiku zmizení View, protože onDisappear negarantuje volání při minimalizaci aplikace.

Vlastnost.onAppear.onDisappear
Okamžik voláníPřidání View do hierarchieOdstranění View z hierarchie
PořadíParent-firstChild-first
ZárukaVysokáNe při nouzovém ukončení
Hlavní úkolInicializaceČištění
Opakované voláníPři regeneraci ViewJednorázově na zmizení

Doporučení: používejte onDisappear pouze pro nekritické čištění a sledování. Pro ukládání dat používejte scenePhase nebo oznámení applicationWillTerminate v AppDelegate.

Typické scénáře použití

Scénář 1: načítání podobné YouTube. Na obrazovce detailů videa onDisappear ukládá pozici přehrávání do UserDefaults. Při opětovném otevření onAppear obnoví pozici z UserDefaults, čímž vytváří efekt nepřetržitého sledování.

Scénář 2: zrušení Combine odběru. Pokud ViewModel používá Combine publikery, onDisappear ruší odběr pomocí cancellable?.cancel(). Tím se zabrání aktualizaci UI po opuštění obrazovky, což je důležité zejména pro seznamy s stránkováním a vyhledávací dotazy.

Scénář 3: zavření WebSocket. V aplikacích s připojením v reálném čase (messengery, kanály kotací) onDisappear zavírá WebSocket připojení pro úsporu baterie a přenosu dat. Opětovné otevření probíhá v onAppear při návratu na obrazovku.

Zavření WebSocket v onDisappear

WebSocket — typický zdroj, který by měl být uzavřen při opuštění obrazovky. V níže uvedeném příkladu onDisappear odpojuje socket a onAppear ho znovu připojuje, což poskytuje významnou úsporu přenosu dat pro aplikace s více obrazovkami.

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

Důležité: při přepínání mezi kartami TabView se onDisappear aktuální karty a onAppear následující karty spouští téměř současně. Pro WebSocket to může vést k cyklu disconnect-connect, který vytváří dodatečnou zátěž. Řešení — použití zpoždění nebo kontrola, zda je socket potřeba na následující obrazovce.

Často kladené otázky

Může se .onDisappear nevyvolat?

Ano, .onDisappear negarantuje volání při nouzovém ukončení aplikace (crash, watchdog kill), minimalizaci aplikace bez zavření obrazovky nebo systémovém scénáři, při kterém je aplikace zničena na pozadí. Pro kriticky důležitá data používejte scenePhase nebo applicationWillTerminate.

Jak odlišit .onDisappear od .scenePhase?

.onDisappear se spouští při odstranění View z hierarchie — lokální zpětné volání pro konkrétní obrazovku. .scenePhase (přes @Environment(\.scenePhase)) se spouští při změně stavu celé aplikace: active, inactive, background. Pro sledování času na obrazovce používejte onAppear+onDisappear, pro ukládání globálního stavu — scenePhase.

Proč se .onDisappear volá několikrát za sebou?

Příčinou je rychlé přepínání mezi kartami nebo opakovaný push/pop stejné obrazovky. SwiftUI může vytvořit novou instanci View, odstranit starou, vytvořit znovu — pokaždé spouštějící onDisappear a onAppear. Zkontrolujte, zda nepoužíváte .id(), .equatable() nebo zda znovu nevytváříte View v těle rodiče.

Funguje .onDisappear ve SwiftUI na macOS?

Ano, .onDisappear je plně podporován na macOS (10.15+) se stejným chováním: volá se při zavření okna, odstranění panelu split view nebo dismiss modálního okna. Na macOS se onDisappear volá také při skrytí okna (hide), nejen při zavření, což je důležité pro macOS aplikace.

Jak zrušit URLSessionTask v .onDisappear?

Uložte referenci na URLSessionTask do @State a zavolejte task.cancel() v onDisappear. Alternativně použijte modifikátor .task, který automaticky ruší async operaci při zmizení View. .task je preferovaný pro všechny async operace, včetně URLSession.

Shrnutí

  • .onDisappear — párový modifikátor k onAppear pro čištění zdrojů a sledování při zmizení View.
  • Child-first pořadí — podřízené View dostávají onDisappear dříve než rodič pro správný řetězec uvolňování.
  • Žádná záruka volání — při crash, minimalizaci nebo systémovém ukončení onDisappear nemusí fungovat.
  • Hlavní scénáře — rušení časovačů, zavírání WebSocket, ukládání stavu, sledování délky.
  • Analytika — onDisappear odesílá události screen_close s výpočtem dwell time přes Date().timeIntervalSince.
  • Pro async operace — používejte .task místo onDisappear s Task {}, protože .task automaticky ruší požadavky.

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také