.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 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í.
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ě.
struct DetailView: View {
var body: some View {
Text("Obrazovka detailů")
.onDisappear {
print("DetailView zmizel z obrazovky")
}
}
}
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í 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.
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í.
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 NavigationStack | Ano | Ihned po animaci |
| Přepnutí karty TabView | Ano | Aktuální karta |
| Dismiss sheet | Ano | Před dokončením animace |
| Scroll v List | Ano | Buňka opustila prefetch zónu |
| Minimalizace aplikace | Ne | Žádná záruka volání |
| Crash/watchdog kill | Ne | Nevolá se |
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 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.
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í.
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.
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)
])
}
}
}
}
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 hierarchie | Odstranění View z hierarchie |
| Pořadí | Parent-first | Child-first |
| Záruka | Vysoká | Ne při nouzovém ukončení |
| Hlavní úkol | Inicializace | Čištění |
| Opakované volání | Při regeneraci View | Jednorá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.
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.
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.
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
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.
.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.
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.
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.
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í
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í.
Přečtěte si také