.onDisappear — modifier SwiftUI yang mengeksekusi closure ketika View dihapus dari hierarki antarmuka. Panggilan terjadi saat menutup layar, mengganti tab, dismiss jendela modal, atau scroll elemen keluar dari area pandang. Menurut Apple Developer Documentation (2026), onDisappear tidak menjamin panggilan dalam skenario penghentian darurat atau saat aplikasi dihancurkan oleh system-watchdog. Baca lebih lanjut tentang SwiftUI di materi tentang SwiftUI.
Poin Utama
.onDisappear — modifier View di SwiftUI yang menerima closure Void dan mengeksekusinya saat View dihapus dari hierarki. Berpasangan dengan .onAppear membentuk siklus hidup layar lengkap: kemunculan — kerja — penghilangan. Apple memperkenalkan onDisappear bersamaan dengan rilis SwiftUI di iOS 13 sebagai analog viewDidDisappear dari UIKit.
Secara sintaksis .onDisappear identik dengan onAppear: memodifikasi View apa pun dan melampirkan closure yang dipanggil oleh komponen SwiftUI saat tampilan dihapus. Berbeda dengan UIKit di mana viewDidDisappear hanya aktif setelah animasi transisi selesai, onDisappear di SwiftUI dapat dipanggil sebelum animasi selesai — saat View ditandai untuk dihapus.
Sintaks dasar onDisappear sama ringkasnya dengan onAppear. Modifier tidak menerima parameter tambahan — hanya closure yang dieksekusi secara sinkron di thread utama.
struct DetailView: View {
var body: some View {
Text("Layar Detail")
.onDisappear {
print("DetailView menghilang dari layar")
}
}
}
Mekanisme panggilan onDisappear kebalikan dari onAppear: pertama elemen anak menerima onDisappear, kemudian induk. Aturan child-first ini memastikan bahwa sumber daya elemen anak dibebaskan sebelum sumber daya induk dibebaskan. Jika elemen anak bergantung pada data induk, ia harus dapat menyelesaikan dengan benar tanpa konteks induk.
SwiftUI memanggil onDisappear saat View dikeluarkan dari grafis render. Pemicunya bisa berupa: pop dari NavigationStack, pergantian TabView, dismiss jendela modal (sheet/fullScreenCover), perubahan View yang ditampilkan bersyarat (if/switch). Di List dan ScrollView onDisappear dipanggil saat sel di-scroll keluar dari buffer prefetch.
Urutan child-first berarti jika ada tiga View anak di VStack, onDisappear akan dipanggil pertama untuk setiap anak dalam urutan terbalik, kemudian untuk induk. Ini penting untuk pembersihan yang benar: timer anak dibatalkan sebelum ViewModel induk membebaskan sumber daya bersama.
struct ParentView: View {
var body: some View {
VStack {
ChildView(id: "A")
ChildView(id: "B")
}
.onDisappear {
print("Parent onDisappear — terakhir")
}
}
}
struct ChildView: View {
let id: String
var body: some View {
Text("Anak \(id)")
.onDisappear {
print("Anak \(id) onDisappear")
}
}
}
Keluaran konsol: Child B onDisappear, Child A onDisappear, Parent onDisappear — terakhir. Urutan terbalik dibandingkan dengan onAppear memastikan rantai pembebasan yang benar.
Skenario panggilan onDisappear tergantung pada jenis kontainer. Di NavigationStack onDisappear dipicu saat pop-to-root, pop-back biasa, atau penghapusan layar dengan gesture geser (interactivePopGestureRecognizer). Di TabView pergantian tab memicu onDisappear untuk yang disembunyikan dan onAppear untuk yang ditampilkan — kedua modifier dipicu hampir bersamaan.
Di Sheet dan fullScreenCover onDisappear dipanggil saat dismiss terprogram (melalui @Environment(\.dismiss)) atau gesture geser ke bawah. Fitur penting: jika sheet telah dibuka tetapi pengguna mengganti aplikasi, onDisappear TIDAK dipanggil sampai penutupan sebenarnya.
| Skenario | onDisappear dipanggil | Catatan |
|---|---|---|
| Pop di NavigationStack | Ya | Segera setelah animasi |
| Pergantian tab TabView | Ya | Tab saat ini |
| Dismiss sheet | Ya | Sebelum animasi selesai |
| Scroll di List | Ya | Sel keluar dari zona prefetch |
| Meminimalkan aplikasi | Tidak | Tidak ada jaminan panggilan |
| Crash/watchdog kill | Tidak | Tidak dipanggil |
Skenario utama onDisappear — pembersihan sumber daya, penyimpanan status, dan pelacakan. Berbeda dengan onAppear, tugas onDisappear dieksekusi saat keluar dan tidak memerlukan pemeriksaan duplikasi, karena View menghilang satu kali.
Menyimpan status di onDisappear sangat berguna untuk formulir di mana data harus disimpan saat meninggalkan layar. Timer dan langganan Combine dibatalkan di onDisappear untuk menghindari kebocoran memori saat kembali ke layar.
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")
}
}
Pembatalan timer di onDisappear mencegah eksekusi kode setelah layar ditutup. Tanpa pembatalan, timer dapat mencoba memperbarui @State yang sudah tidak dimiliki View saat ini, menyebabkan runtime warning.
Durasi tinggal di layar — skenario pelacakan klasik. Kami mencatat waktu di onAppear, menghitung selisih di onDisappear, dan mengirim event analitik dengan durasi sesi.
struct TrackedView: View {
@State private var appearTime: Date?
var body: some View {
Text("Layar yang Dilacak")
.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)
])
}
}
}
}
Perbedaan utama onDisappear dengan onAppear — urutan panggilan dan jaminan pengaktifan. onAppear dipanggil saat View ditambahkan ke hierarki dan memiliki sifat panggilan ulang saat dibuat ulang. onDisappear dipanggil saat penghapusan dan dijamin hanya berfungsi pada penutupan normal, tetapi tidak dalam skenario darurat.
Menurut WWDC 2024, Apple merekomendasikan untuk menganggap onDisappear sebagai titik pembersihan, bukan titik penyimpanan data. Data yang sangat penting (pembayaran, pendaftaran) harus disimpan secara real-time, bukan saat View menghilang, karena onDisappear tidak menjamin panggilan saat aplikasi diminimalkan.
| Karakteristik | .onAppear | .onDisappear |
|---|---|---|
| Saat dipanggil | View ditambahkan ke hierarki | View dihapus dari hierarki |
| Urutan | Parent-first | Child-first |
| Jaminan | Tinggi | Tidak pada penghentian darurat |
| Tugas utama | Inisialisasi | Pembersihan |
| Panggilan ulang | Saat View dibuat ulang | Sekali per penghilangan |
Rekomendasi: gunakan onDisappear hanya untuk pembersihan dan pelacakan yang tidak kritis. Untuk menyimpan data gunakan scenePhase atau pemberitahuan applicationWillTerminate di AppDelegate.
Skenario 1: pemuatan seperti YouTube. Di layar detail video onDisappear menyimpan posisi pemutaran di UserDefaults. Saat dibuka kembali, onAppear memulihkan posisi dari UserDefaults, memberikan efek menonton berkelanjutan.
Skenario 2: pembatalan langganan Combine. Jika ViewModel menggunakan publisher Combine, onDisappear membatalkan langganan melalui cancellable?.cancel(). Ini mencegah pembaruan UI setelah meninggalkan layar, yang sangat penting untuk daftar dengan paginasi dan kueri pencarian.
Skenario 3: menutup WebSocket. Di aplikasi dengan koneksi real-time (messenger, feed harga) onDisappear menutup koneksi WebSocket untuk menghemat baterai dan trafik. Pembukaan kembali dilakukan di onAppear saat kembali ke layar.
WebSocket — sumber daya umum yang perlu ditutup saat meninggalkan layar. Dalam contoh di bawah onDisappear memutuskan socket, dan onAppear menghubungkannya kembali, memberikan penghematan trafik yang signifikan untuk aplikasi dengan banyak layar.
struct ChatView: View {
@StateObject private var socket = WebSocketManager()
var body: some View {
ChatListView(messages: socket.messages)
.onAppear {
socket.connect()
}
.onDisappear {
socket.disconnect()
}
}
}
Penting: saat beralih antar tab di TabView, onDisappear tab saat ini dan onAppear tab berikutnya dipicu hampir bersamaan. Untuk WebSocket ini dapat menyebabkan siklus disconnect-connect yang menimbulkan beban tambahan. Solusi — gunakan penundaan atau periksa apakah socket diperlukan di layar berikutnya.
Pertanyaan yang Sering Diajukan
Ya, .onDisappear tidak menjamin panggilan saat penghentian darurat aplikasi (crash, watchdog kill), meminimalkan aplikasi tanpa menutup layar, atau skenario sistem di mana aplikasi dihancurkan di latar belakang. Untuk data yang sangat penting gunakan scenePhase atau applicationWillTerminate.
.onDisappear dipicu saat View dihapus dari hierarki — callback lokal untuk layar tertentu. .scenePhase (melalui @Environment(\.scenePhase)) dipicu saat status seluruh aplikasi berubah: active, inactive, background. Untuk melacak waktu di layar gunakan onAppear+onDisappear, untuk menyimpan status global — scenePhase.
Penyebabnya — perpindahan cepat antar tab atau push/pop berulang pada layar yang sama. SwiftUI dapat membuat instance View baru, menghapus yang lama, membuat lagi — setiap kali memicu onDisappear dan onAppear. Periksa apakah Anda menggunakan .id(), .equatable() atau membuat ulang View di body induk.
Ya, .onDisappear sepenuhnya didukung di macOS (10.15+) dengan perilaku yang sama: dipanggil saat menutup jendela, menghapus panel split view, atau dismiss jendela modal. Di macOS onDisappear juga dipanggil saat menyembunyikan jendela (hide), tidak hanya saat menutup, yang penting untuk aplikasi macOS.
Simpan referensi ke URLSessionTask di @State dan panggil task.cancel() di onDisappear. Alternatifnya, gunakan modifier .task yang secara otomatis membatalkan operasi async saat View menghilang. .task lebih disukai untuk semua operasi async, termasuk URLSession.
Ringkasan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga