defer — konstruksi kontrol di Swift yang menjadwalkan eksekusi blok kode pada saat keluar dari lingkup visibilitas saat ini (scope). Blok defer dieksekusi terlepas dari cara penghentiannya — return, break, throw, fatalError atau penghentian normal. Menurut Swift Language Guide (2025), ketika ada beberapa defer dalam satu scope, mereka dieksekusi dalam urutan deklarasi terbalik — yang terakhir dideklarasikan dieksekusi pertama (LIFO). Ini membuat defer sangat diperlukan untuk pembersihan sumber daya yang terjamin: menutup deskriptor file, melepas kunci, membebaskan pointer sementara tanpa risiko melewatkan cleanup saat keluar lebih awal.
Utama
defer — adalah konstruksi kontrol bahasa Swift, diperkenalkan di Swift 2.0 (2015), yang menunda eksekusi bloknya sampai saat scope saat ini berakhir. Fitur utama: defer menjamin eksekusi tubuhnya terlepas dari bagaimana tepatnya scope berakhir — berhasil (return), dengan kesalahan (throw), lebih awal (break, continue) atau fatal (fatalError, precondition).
Secara sintaks defer terlihat seperti defer { /* kode */ } dan dapat ditempatkan di mana saja di dalam scope. Kompiler Swift menjamin bahwa kode di dalam defer akan dieksekusi, bahkan jika antara deklarasi defer dan akhir scope terjadi pengecualian atau return. Ini membedakan defer secara fundamental dari kode biasa yang ditempatkan di akhir fungsi, yang dapat dilewati saat keluar lebih awal.
Menurut artikel Chris Lattner (Pencipta Swift, 2015), defer terinspirasi oleh konstruksi serupa di bahasa lain — defer di Go, finally di Java/Python, scope guard di C++ — tetapi dengan perbedaan penting: di Swift defer dieksekusi di akhir scope, bukan segera setelah blok try-catch. Ini memberikan perilaku yang lebih dapat diprediksi untuk cleanup di fungsi dengan banyak titik keluar.
Gunakan defer untuk manajemen sumber daya yang simetris: membuka file → defer { close }, mengatur kunci → defer { unlock }. Pola semacam itu menjamin bahwa pembebasan sumber daya tidak akan terlewatkan dalam keadaan apapun.
Ketika beberapa defer dideklarasikan dalam satu scope, mereka dieksekusi dalam urutan terbalik deklarasi (LIFO — Last In, First Out). Ini berarti defer yang terakhir dideklarasikan akan dieksekusi pertama, dan yang pertama — terakhir:
func exampleDeferOrder() {
defer { print("Defer pertama") }
defer { print("Defer kedua") }
defer { print("Defer ketiga") }
print("Tubuh fungsi")
}
// Keluaran:
// Tubuh fungsi
// Defer ketiga
// Defer kedua
// Defer pertama
Urutan LIFO penting untuk manajemen sumber daya bersarang yang benar. Jika pertama file A dibuka, kemudian file B, mereka harus dibebaskan dalam urutan terbalik: pertama B, lalu A. Dengan defer ini terjadi secara otomatis — deklarasikan defer segera setelah membuka setiap sumber daya, dan urutan pembersihan akan benar terlepas dari jumlah titik keluar dari fungsi.
Menurut Swift by Sundell (2024), fitur ini membuat defer ideal untuk kunci bersarang dan transaksi: mengambil kunci → defer { unlock } → mengambil berikutnya → defer { unlock }. LIFO menjamin bahwa kunci dibebaskan dalam urutan terbalik dari pengambilan, mencegah deadlock.
Penggunaan utama defer — pembersihan sumber daya yang terjamin. Mari kita lihat bekerja dengan sistem file. Membuka file melalui FileHandle memerlukan penutupan eksplisit — defer menjamin bahwa close akan dipanggil dalam skenario apapun:
func readFile(path: String) throws -> String {
let handle = try FileHandle(forReadingFrom: URL(fileURLWithPath: path))
defer { try? handle.close() }
let data = try handle.readToEnd()
guard let data else { throw FileError.empty() }
return String(data: data, encoding: .utf8) ?? ""
// handle.close() akan dipanggil bahkan saat throw atau return
}
Skenario khas lainnya — animasi UI dengan bendera pemuatan. Sebelum memulai pemuatan, bendera isLoading = true diatur, dan defer mengubahnya menjadi false saat keluar dari fungsi, terlepas dari keberhasilan atau kesalahan permintaan. Ini mencegah situasi di mana bendera tetap true karena kesalahan yang tidak ditangani dan memblokir antarmuka selamanya.
Menurut Bitbucket Engineering Blog (2024), defer juga digunakan untuk pembuatan profil: di awal fungsi dapat mencatat waktu, dan di defer — menghitung dan menampilkan perbedaannya. Ini memberikan pengukuran kinerja yang akurat untuk semua jalur eksekusi, termasuk yang salah.
defer secara efektif dikombinasikan dengan fungsi throws. Ketika sebuah fungsi dapat melempar kesalahan pada tahap apapun, defer menjamin cleanup tanpa menduplikasi kode di setiap blok catch atau keluar awal guard:
func processTransaction() throws {
let db = try openDatabase()
defer { closeDatabase(db) }
let user = try fetchUser(from: db)
defer { logAudit(user) }
let result = try performPayment(user)
sendNotification(result)
// closeDatabase(db) dan logAudit(user) akan dipanggil
// pada setiap throw atau return
}
Penting: defer dieksekusi sebelum transfer kontrol dari blok catch, tetapi setelah terjadinya kesalahan. Jika kesalahan dilempar di defer, Swift tidak mengizinkan penggunaan try di dalam defer secara langsung — diperlukan try? atau try!. Menurut Apple Documentation, Swift tidak mengizinkan kesalahan „keluar" dari defer, karena ini akan melanggar jaminan eksekusi blok.
Tempatkan defer segera setelah mengambil sumber daya. Ini mengikuti prinsip kedekatan: pembaca melihat pengambilan dan pembebasan berdampingan, yang meningkatkan keandalan kode dan menyederhanakan peninjauan kode.
defer dieksekusi saat keluar dari scope di mana ia dideklarasikan. Jika defer dideklarasikan di dalam blok do, ia dieksekusi saat keluar dari blok ini, bukan dari fungsi luar. Jika di dalam loop for — pada setiap iterasi:
func scopeExample() {
print("start")
do {
defer { print("defer blok do") }
print("inside do")
}
// "defer blok do" mencetak di sini
print("after do")
}
// Keluaran: start, inside do, defer blok do, after do
for i in 1...3 {
defer { print("end iteration \(i)") }
print("iteration \(i)")
}
// Keluaran: iterasi 1, akhir iterasi 1, iterasi 2, akhir iterasi 2, ...
Variabel yang ditangkap oleh defer dibaca pada saat keluar dari scope, bukan pada saat deklarasi defer. Jika variabel berubah antara deklarasi defer dan akhir scope, defer akan melihat nilai terakhir. Ini adalah perbedaan penting dari closure, di mana penangkapan terjadi pada saat pembuatan. Berhati-hatilah: perubahan variabel setelah deklarasi defer akan mempengaruhi eksekusinya.
Kesalahan pertama — asumsi tentang urutan eksekusi yang berbeda dari LIFO. Jika urutan cleanup penting dan defer dideklarasikan dalam urutan yang salah, sumber daya dapat dibebaskan dengan melanggar ketergantungan. Solusi: deklarasikan defer segera setelah mengambil setiap sumber daya. Sumber daya kedua dibuka → defer { close second } sebelum yang pertama ditutup.
Kesalahan kedua — menggunakan defer untuk logika yang tidak terkait dengan pembersihan. defer dirancang untuk cleanup yang terjamin, bukan untuk aliran kontrol utama. Jika kode di defer mempengaruhi nilai yang dikembalikan, ini hampir selalu kesalahan. defer tidak dapat mengubah nilai return fungsi (tidak seperti Java finally, di mana return di finally menimpa return asli).
Kesalahan ketiga — melempar kesalahan dari defer. Swift melarang try di dalam defer jika kesalahan dapat menyebar ke luar. Gunakan try? atau try! untuk operasi yang dapat melempar kesalahan, atau bungkus dalam fungsi terpisah tanpa throws. Menurut O'Reilly „Swift in Depth" (2025), praktik yang baik adalah membuat fungsi cleanup non-throwing atau menangani kesalahan di dalam defer.
Pertanyaan yang Sering Diajukan
defer — konstruksi kontrol Swift yang menunda eksekusi blok sampai keluar dari lingkup visibilitas saat ini. Blok selalu dieksekusi — saat return, throw, break atau penghentian normal. Digunakan untuk pembersihan sumber daya yang terjamin: menutup file, melepas kunci.
Dalam urutan deklarasi terbalik (LIFO) — defer yang terakhir dideklarasikan dieksekusi pertama. Ini menjamin pembersihan yang benar dari sumber daya bersarang: jika sumber daya B dibuka setelah A, ia akan ditutup sebelum A, mencegah ketergantungan pada sumber daya yang sudah dibebaskan.
Tidak secara langsung — Swift melarang penyebaran kesalahan dari defer. Gunakan try? atau try! untuk operasi yang dapat melempar kesalahan. Praktik terbaik adalah membuat fungsi cleanup non-throwing atau menangani kesalahan di dalam defer tanpa menyebarkan ke luar.
defer terikat pada scope dan dieksekusi pada setiap keluar, termasuk return, throw dan break. finally (di bahasa lain) terikat pada try-catch dan hanya dieksekusi dengan adanya try. Di Swift tidak ada finally — defer sepenuhnya mencakup skenario ini dan bekerja untuk scope apa pun, bukan hanya untuk penanganan kesalahan.
Ya, defer membaca variabel pada saat keluar dari scope, bukan pada saat deklarasi. Jika variabel berubah setelah deklarasi defer, blok defer akan melihat nilai terakhir. Ini berbeda dari closure biasa, di mana penangkapan ditentukan pada saat pembuatan.
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