.onDisappear — en SwiftUI-modifierare som utför en closure när en View tas bort från gränssnittshierarkin. Anropet sker vid stängning av skärmen, byte av flik, dismiss av modalt fönster eller scrollning av ett element utanför synligt område. Enligt Apple Developer Documentation (2026) garanterar onDisappear inte anrop i scenarier med nödavslutning eller när applikationen förstörs av system-watchdog. Läs mer om SwiftUI i materialet om SwiftUI.
Huvudpunkter
.onDisappear — en View-modifierare i SwiftUI som accepterar en Void-closure och utför den när View tas bort från hierarkin. Tillsammans med .onAppear bildar den en fullständig livscykel för skärmen: uppträdande — arbete — försvinnande. Apple introducerade onDisappear tillsammans med lanseringen av SwiftUI i iOS 13 som en analog till viewDidDisappear från UIKit.
Syntaxmässigt är .onDisappear identisk med onAppear: modifierar vilken View som helst och kopplar en closure som anropas av SwiftUI-komponenten när vyn tas bort. Till skillnad från UIKit där viewDidDisappear aktiveras först efter att övergångsanimationen slutförts, kan onDisappear i SwiftUI anropas innan animationen är klar — i det ögonblick som View markeras för borttagning.
Grundläggande syntax för onDisappear är lika koncis som onAppear. Modifieraren accepterar inga ytterligare parametrar — endast closuren som utförs synkront i huvudtråden.
struct DetailView: View {
var body: some View {
Text("Detaljskärm")
.onDisappear {
print("DetailView försvann från skärmen")
}
}
}
Anropsmekanism för onDisappear är motsatsen till onAppear: först får underordnade element onDisappear, sedan föräldern. Denna child-first-regel garanterar att resurser för underordnade element frigörs innan förälderns resurser frigörs. Om ett underordnat element är beroende av förälderns data måste det kunna avslutas korrekt utan förälderns kontext.
SwiftUI anropar onDisappear i det ögonblick som View utesluts från renderingsgrafen. Utlösaren kan vara: pop från NavigationStack, byte av TabView, dismiss av modalt fönster (sheet/fullScreenCover), ändring av villkorligt visad View (if/switch). I List och ScrollView anropas onDisappear när en cell scrollas utanför prefetch-bufferten.
Child-first-ordning innebär att om det finns tre underordnade Views i en VStack, kommer onDisappear att anropas först för varje barn i omvänd ordning, sedan för föräldern. Detta är kritiskt för korrekt rensning: underordnade timers annulleras innan förälderns ViewModel frigör delade resurser.
struct ParentView: View {
var body: some View {
VStack {
ChildView(id: "A")
ChildView(id: "B")
}
.onDisappear {
print("Parent onDisappear — sist")
}
}
}
struct ChildView: View {
let id: String
var body: some View {
Text("Barn \(id)")
.onDisappear {
print("Barn \(id) onDisappear")
}
}
}
Konsoloutput: Child B onDisappear, Child A onDisappear, Parent onDisappear — sist. Omvänd ordning jämfört med onAppear garanterar en korrekt frigörandekedja.
Anropscenarier för onDisappear beror på containertypen. I NavigationStack utlöses onDisappear vid pop-to-root, vanlig pop-back eller borttagning av skärm genom svepgest (interactivePopGestureRecognizer). I TabView utlöser byte av flik onDisappear för den dolda och onAppear för den visade — båda modifierarna utlöses nästan samtidigt.
I Sheet och fullScreenCover anropas onDisappear vid programmatisk dismiss (via @Environment(\.dismiss)) eller svepgest nedåt. En viktig egenskap: om sheet har öppnats men användaren har bytt app, anropas onDisappear INTE förrän själva stängningen.
| Scenario | onDisappear anropas | Anmärkning |
|---|---|---|
| Pop i NavigationStack | Ja | Omedelbart efter animation |
| Flikbyte i TabView | Ja | Aktuell flik |
| Dismiss av sheet | Ja | Innan animation slutförs |
| Scroll i List | Ja | Cell utanför prefetch-zon |
| Minimering av app | Nej | Ingen garanti för anrop |
| Crash/watchdog kill | Nej | Anropas inte |
Huvudscenarier för onDisappear — rensning av resurser, sparande av tillstånd och spårning. Till skillnad från onAppear utförs onDisappear-uppgifter vid utgång och kräver ingen kontroll för dubbelarbete eftersom View försvinner en gång.
Spara tillstånd i onDisappear är särskilt användbart för formulär där data måste sparas när man lämnar skärmen. Timers och Combine-prenumerationer annulleras i onDisappear för att undvika minnesläckor vid återgång till skärmen.
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")
}
}
Annullering av timer i onDisappear förhindrar att kod körs efter att skärmen stängts. Utan annullering kan timern försöka uppdatera ett @State som inte längre tillhör den aktuella View, vilket orsakar en runtime-varning.
Vistelsetid på skärmen — ett klassiskt spårningscenario. Vi registrerar tiden i onAppear, beräknar skillnaden i onDisappear och skickar en analytisk händelse med sessionens varaktighet.
struct TrackedView: View {
@State private var appearTime: Date?
var body: some View {
Text("Spårad Skärm")
.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)
])
}
}
}
}
Den viktigaste skillnaden mellan onDisappear och onAppear — anropsordningen och aktiveringsgarantierna. onAppear anropas när View läggs till i hierarkin och har egenskapen att återanropas vid återskapande. onDisappear anropas vid borttagning och fungerar garanterat endast vid normal stängning, men inte i nödsituationer.
Enligt WWDC 2024 rekommenderar Apple att onDisappear betraktas som en renspunkt, inte som en datalagringspunkt. Kritisk viktig data (betalningar, registreringar) bör sparas i realtid, inte i ögonblicket när View försvinner, eftersom onDisappear inte garanterar anrop när appen minimeras.
| Egenskap | .onAppear | .onDisappear |
|---|---|---|
| Anropstillfälle | View läggs till i hierarki | View tas bort från hierarki |
| Ordning | Parent-first | Child-first |
| Garanti | Hög | Inte vid nödavslutning |
| Huvuduppgift | Initiering | Rensning |
| Återanrop | Vid återskapande av View | En gång per försvinnande |
Rekommendation: använd onDisappear endast för icke-kritisk rensning och spårning. För att spara data, använd scenePhase eller applicationWillTerminate-meddelanden i AppDelegate.
Scenario 1: YouTube-liknande laddning. På videodetaljskärmen sparar onDisappear uppspelningspositionen i UserDefaults. Vid återöppning återställer onAppear positionen från UserDefaults, vilket ger en kontinuerlig tittarupplevelse.
Scenario 2: annullering av Combine-prenumeration. Om ViewModel använder Combine-publishers, annullerar onDisappear prenumerationen via cancellable?.cancel(). Detta förhindrar UI-uppdateringar efter att skärmen lämnats, vilket är särskilt viktigt för listor med paginering och sökfrågor.
Scenario 3: stängning av WebSocket. I appar med realtidsanslutningar (meddelandetjänster, kursflöden) stänger onDisappear WebSocket-anslutningen för att spara batteri och trafik. Återöppning sker i onAppear vid återgång till skärmen.
WebSocket — en typisk resurs som bör stängas när man lämnar skärmen. I exemplet nedan kopplar onDisappear bort socketen och onAppear återansluter den, vilket ger betydande trafikbesparingar för appar med flera skärmar.
struct ChatView: View {
@StateObject private var socket = WebSocketManager()
var body: some View {
ChatListView(messages: socket.messages)
.onAppear {
socket.connect()
}
.onDisappear {
socket.disconnect()
}
}
}
Viktigt: vid växling mellan flikar i TabView utlöses onDisappear för den aktuella fliken och onAppear för nästa flik nästan samtidigt. För WebSocket kan detta leda till en disconnect-connect-cykel som skapar extra belastning. Lösning — använd en fördröjning eller kontrollera om socketen behövs på nästa skärm.
Vanliga frågor
Ja, .onDisappear garanterar inte anrop vid nödavslutning av appen (crash, watchdog kill), minimering av appen utan att stänga skärmen eller systemscenario där appen förstörs i bakgrunden. För kritisk viktig data, använd scenePhase eller applicationWillTerminate.
.onDisappear utlöses när View tas bort från hierarkin — en lokal callback för en specifik skärm. .scenePhase (via @Environment(\.scenePhase)) utlöses när hela appens tillstånd ändras: active, inactive, background. För spårning av tid på skärmen, använd onAppear+onDisappear, för lagring av globalt tillstånd — scenePhase.
Orsaken — snabb växling mellan flikar eller upprepad push/pop av samma skärm. SwiftUI kan skapa en ny View-instans, ta bort den gamla, skapa igen — varje gång utlöses onDisappear och onAppear. Kontrollera om du använder .id(), .equatable() eller om du återskapar View i förälderns body.
Ja, .onDisappear stöds fullt ut på macOS (10.15+) med samma beteende: anropas vid stängning av fönster, borttagning av split view-panel eller dismiss av modalt fönster. På macOS anropas onDisappear även vid döljande av fönster (hide), inte bara vid stängning, vilket är viktigt för macOS-applikationer.
Spara referensen till URLSessionTask i @State och anropa task.cancel() i onDisappear. Alternativt, använd .task-modifieraren som automatiskt annullerar async-operationen när View försvinner. .task är att föredra för alla async-operationer, inklusive URLSession.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också