defer — apa itu, sintaks dan urutan eksekusi

Penulis: IT Sectr Diterbitkan: 2026-06-20 Waktu membaca: 8 mnt

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 — blok kode yang dieksekusi saat keluar dari lingkup visibilitas, terlepas dari alasan keluar (return, throw, break)
  • Urutan LIFO: beberapa defer dieksekusi dari bawah ke atas — yang terakhir dideklarasikan dipicu pertama
  • Pembersihan sumber daya — penggunaan utama: menutup file, melepas kunci, mengakhiri animasi
  • Definisi variabel: defer melihat variabel pada saat keluar, bukan pada saat deklarasi
  • Tidak menggantikan do-catch untuk penanganan kesalahan — defer bertanggung jawab untuk cleanup, bukan untuk kontrol aliran

Apa itu defer?

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.

Urutan eksekusi beberapa defer

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:

swift
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.

Defer untuk pembersihan sumber daya

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:

swift
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 dan penanganan kesalahan

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:

swift
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.

Aturan lingkup visibilitas

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:

swift
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 umum dengan defer

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

Apa itu defer di Swift?

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 apa beberapa defer dieksekusi?

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.

Bisakah kesalahan dilempar dari defer?

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.

Apa perbedaan antara defer dan do-catch-finally?

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.

Apakah defer melihat perubahan variabel setelah deklarasinya?

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

  • defer — blok finalisasi yang dieksekusi saat keluar dari scope terlepas dari alasan (return, throw, break, penghentian normal)
  • Urutan LIFO — beberapa defer dieksekusi dari bawah ke atas, terakhir dideklarasikan — pertama dieksekusi
  • Pembersihan sumber daya — penggunaan utama: menutup file, melepas kunci, membebaskan pointer, menghentikan animasi
  • Kompatibilitas dengan throws: defer dieksekusi setelah kesalahan tetapi sebelum keluar dari blok catch; kesalahan dari defer tidak menyebar
  • Scope: defer dieksekusi saat keluar dari scope di mana ia dideklarasikan — blok do, loop, fungsi
  • Penangkapan variabel: defer membaca nilai pada saat keluar, bukan pada saat deklarasi — perhatikan mutasi
  • Praktik terbaik: deklarasikan defer segera setelah mengambil sumber daya, jangan gunakan defer untuk logika bisnis, buat fungsi cleanup non-throwing

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.

Diskusikan proyek

Baca juga