Weak Reference — apa itu, sintaksis dan penerapan dalam pengembangan mobile

Penulis: IT Sectr Diterbitkan: 2026-03-30 Waktu membaca: 9 mnt

Weak Reference (referensi lemah) — adalah referensi ke objek yang tidak meningkatkan penghitung retensinya di ARC. Menurut Apple Swift Language Guide, 2026, referensi weak dideklarasikan dengan kata kunci weak dan selalu memiliki tipe opsional. Ketika objek dibebaskan, semua referensi weak ke objek tersebut secara otomatis diatur ke nil, yang mencegah dangling pointer dan menjadikan referensi lemah mekanisme aman untuk memutus retain cycle.

Utama

  • Weak Reference — referensi yang tidak mempengaruhi retain count objek; saat objek dibebaskan menjadi nol
  • Deklarasi — kata kunci weak sebelum var; tipe selalu opsional (?)
  • Penerapan — delegat, closure, hubungan parent-child untuk memutus retain cycle
  • Keamanan — pengaturan otomatis ke nil setelah dealokasi objek (zeroing weak)
  • Perbedaan dari unowned — weak menjadi nol dan aman, unowned tidak menjadi nol dan memerlukan jaminan masa hidup

Apa itu Weak Reference?

Weak Reference — adalah referensi tidak memiliki ke objek di ARC (Automatic Reference Counting). Berbeda dengan referensi strong yang meningkatkan retain count objek dan menjamin hidupnya, referensi weak memungkinkan objek dibebaskan meskipun masih ada referensi ke objek tersebut. Setelah dibebaskan, referensi weak secara otomatis diatur ke nil — ini disebut zeroing weak.

Zeroing weak — fitur kunci runtime Swift dan Objective-C. Ketika penghitung referensi objek mencapai nol dan objek didealokasi, runtime menelusuri semua referensi weak ke objek ini (disimpan dalam tabel weak khusus) dan mengaturnya ke nil. Ini menjamin bahwa akses ke memori yang dibebaskan (use-after-free) tidak mungkin melalui referensi weak — pembacaan apa pun mengembalikan nil.

Menurut Apple WWDC 2012 Session 406, referensi zeroing weak menghilangkan seluruh kelas bug crash terkait dangling pointer, yang umum dalam manajemen memori manual (MRR). Di MRR referensi lemah hanya ada sebagai __unsafe_unretained — mereka tidak menjadi nol dan akses ke objek yang dibebaskan menyebabkan EXC_BAD_ACCESS.

Sintaksis weak di Swift dan Objective-C

Mari kita lihat sintaksis deklarasi referensi weak di kedua bahasa ekosistem Apple. Meskipun runtime-nya sama, sintaksisnya berbeda, tetapi semantiknya identik.

Swift

Di Swift referensi weak dideklarasikan dengan kata kunci weak sebelum var. Tipe harus selalu opsional (Type?), karena referensi dapat menjadi nol kapan saja. Konstanta (let) tidak bisa weak — hanya variabel.

swift
class ViewController: UIViewController {
    // properti weak: hanya var, hanya optional
    weak var delegate: ViewControllerDelegate?
    weak var parentView: UIView?

    weak var completionHandler: ((Bool) -> Void)?  // ⚠️ closure tidak menyimpan weak
    // ⬆️ Kesalahan: weak hanya dapat diterapkan ke class-types, bukan ke closure
}

Penting: weak hanya berlaku untuk instance kelas (class-types), AnyObject dan protokol yang mewarisi dari AnyObject. Struct, enum dan closure tidak bisa weak — mereka adalah tipe nilai dan tidak berpartisipasi dalam ARC.

Objective-C

Di Objective-C properti weak dideklarasikan melalui atribut __weak atau pengubah weak di property:

objective-c
// Objective-C: weak property
@interface MyViewController : UIViewController
@property (weak, nonatomic) id<MyDelegate> delegate;
@end

// Variabel weak lokal
__weak MyObject *weakRef = someStrongObject;

Runtime Objective-C juga menyediakan zeroing weak, tetapi juga memblokir penggunaan weak dengan struktur C dan beberapa objek Core Foundation. Untuk mereka digunakan __unsafe_unretained — tanpa zeroing.

Kapan menggunakan referensi lemah

Referensi lemah — bukan solusi universal, melainkan alat untuk skenario tertentu. Menggunakan weak di mana-mana menyebabkan kompleksitas berlebihan dan mengurangi keterbacaan. Mari kita lihat skenario penerapan yang benar.

Delegat (Delegate pattern)

Delegat — skenario utama untuk weak. Objek pemilik (misalnya UITableView) menyimpan referensi strong ke dirinya sendiri, dan delegat (UIViewController) tidak boleh memiliki tabel. Apple SDK menjamin bahwa semua delegate dan dataSource bersifat weak. Untuk protokol Anda sendiri selalu gunakan weak var delegate.

Parent-Child dengan umpan balik

Ketika objek anak perlu merujuk ke induk (misalnya ChildViewController untuk akses ke koordinator), gunakan referensi weak. Induk memiliki anak (strong), anak mengamati induk (weak) — retain cycle dikecualikan.

Closure asinkron

Capture list [weak self] — cara standar untuk menghindari retain cycle di closure yang disimpan sebagai properti kelas. Jika self dapat dibebaskan sebelum closure selesai — weak self wajib.

SkenarioWeakStrong
Delegate✅ Selalu weak❌ Retain cycle
Parent → Child❌ Tidak perlu (induk harus memiliki)✅ Strong
Child → Parent✅ Weak❌ Retain cycle
Callback asinkron✅ [weak self]❌ Risiko retain cycle
Ikatan kuat (owned)❌ unowned✅ Strong

Aturan umum: jika objek A memiliki B (A → B strong), maka B → A harus weak atau unowned. Arah referensi strong harus selalu dari pemilik ke bawahan.

Weak vs Unowned: perbandingan dan skenario

Baik weak maupun unowned tidak meningkatkan retain count, tetapi berbeda dalam perilaku setelah dealokasi objek. Pilihan di antara mereka adalah masalah jaminan masa hidup.

Perbedaan

Weak: secara otomatis menjadi nol (nil), tipe selalu optional, memerlukan unwrap sebelum digunakan. Aman — akses ke nil tidak menyebabkan crash.

Unowned: tidak menjadi nol, tipe non-optional. Jika objek telah dibebaskan, referensi unowned menjadi dangling pointer — akses ke sana menyebabkan runtime crash. Unowned mengasumsikan bahwa objek hidup tidak lebih pendek dari pihak yang mereferensikan.

Kapan memilih weak

Weak pilih jika: objek dapat didealokasi kapan saja (delegat setelah menutup layar), Anda tidak mengontrol masa hidup objek, atau ragu tentang jaminan. Weak — pilihan aman universal.

Kapan memilih unowned

Unowned pilih jika: objek dijamin tidak dapat dibebaskan lebih awal dari yang mereferensikan (misalnya Customer → CreditCard, di mana kartu tidak ada tanpa pelanggan). Unowned memberikan API non-optional tanpa unwrap, yang lebih nyaman dalam kode.

swift
class Order {
    let id: Int
    var items: [Item] = []

    init(id: Int) { self.id = id }

    // Ikatan kuat: Order memiliki Item
    func addItem(name: String) {
        let item = Item(name: name, order: self)
        items.append(item)
    }
}

class Item {
    let name: String
    unowned let order: Order          // ✅ unowned — Item tidak hidup tanpa Order

    init(name: String, order: Order) {
        self.name = name
        self.order = order
    }
}

// Contoh dengan weak: delegat tanpa jaminan masa hidup
protocol NetworkServiceDelegate: AnyObject {
    func didReceiveResponse(data: Data)
}

class NetworkService {
    weak var delegate: NetworkServiceDelegate?  // ✅ weak — delegat bisa pergi
}

Dalam contoh Item menggunakan unowned, karena elemen pesanan tidak dapat ada tanpa pesanan itu sendiri — jaminan masa hidup sangat kuat. NetworkService menggunakan weak, karena delegat (misalnya ViewController) dapat ditutup dan dibebaskan kapan saja.

Keterbatasan referensi weak dan jebakan

Referensi lemah — alat yang kuat, tetapi memiliki keterbatasan yang penting dipahami untuk penerapan yang benar dalam pengembangan iOS.

Kinerja weak

Referensi lemah lebih lambat dari strong: setiap akses runtime memeriksa apakah objek telah dibebaskan (lookup di tabel weak). Di sebagian besar skenario perbedaannya tidak terasa, tetapi di loop panas dengan jutaan akses weak bisa menjadi hambatan. Untuk skenario dengan beban tinggi gunakan strong dan reorganisasi arsitektur.

Weak tidak berlaku untuk tipe nilai

Struct, enum, tuple — tipe nilai yang tidak berpartisipasi dalam ARC. Mencoba mendeklarasikan weak struct menyebabkan kesalahan kompilasi. Untuk menyimpan referensi lemah ke tipe nilai gunakan pembungkus dalam class-type atau closure.

Weak dalam multi-threading

Zeroing weak aman untuk thread: jika objek dibebaskan di satu thread, referensi weak menjadi nol di semua thread secara atomik. Namun jarak antara membaca referensi weak dan menggunakannya dapat menyebabkan kondisi balapan — objek dibebaskan antara mendapatkan referensi weak dan menggunakannya. Solusi: strong-pengambilan referensi lemah ke variabel lokal.

swift
// Kondisi balapan dengan weak di multi-threading
func performAsync() {
    weak var weakSelf = self
    queue.async {
        // ⚠️ weakSelf bisa nil antara pemeriksaan dan penggunaan
        if weakSelf != nil {
            weakSelf!.doSomething()  // CRASH jika menjadi nil
        }
    }
}

// ✅ Perbaikan: pengambilan kuat untuk durasi penggunaan
func performAsyncSafe() {
    queue.async { [weak self] in
        guard let strongSelf = self else { return }
        strongSelf.doSomething()  // strongSelf — referensi strong lokal
    }
}

Dalam varian aman weak self diambil, kemudian segera dibuka ke variabel strong lokal strongSelf. Jika self masih hidup — akan tetap hidup selama eksekusi blok. Jika tidak — guard aktif dan kode tidak dijalankan. Idiom ini — pola standar untuk closure asinkron di Swift.

UIView dan weak outlet

IBOutlet di Interface Builder harus weak, karena hierarki view sudah menyimpan referensi strong ke subview. Menduplikasi referensi strong di kontroler tidak membuat retain cycle, tetapi berlebihan. Referensi lemah ke outlet — rekomendasi Apple, meskipun banyak pengembang menggunakan strong untuk menyederhanakan kode.

Pertanyaan yang Sering Diajukan

Bisakah referensi weak menunjuk ke objek yang belum dibuat?

Tidak, weak hanya bisa menunjuk ke objek yang ada atau nil. Saat membuat objek baru, Anda mendapatkan referensi strong terlebih dahulu (melalui inisialisasi), dan baru kemudian dapat menetapkan referensi lemah. weak nil di awal — keadaan normal.

Mengapa weak hanya bekerja dengan class-types?

Weak didasarkan pada ARC yang hanya mengelola tipe referensi (kelas). Tipe nilai (struct, enum) disalin saat ditugaskan dan tidak memiliki retain count. Untuk hubungan lemah tipe nilai gunakan closure atau pembungkus di class dengan properti weak.

Bagaimana weak mempengaruhi kinerja dalam loop?

Setiap akses ke referensi weak melakukan lookup di tabel runtime. Dalam loop dengan jutaan iterasi ini bisa 2–5 kali lebih lambat dari referensi strong. Untuk jalur panas salin weak ke variabel strong lokal sebelum loop.

Kapan referensi weak bisa menjadi nil secara tidak terduga?

Ketika semua referensi strong ke objek hilang — di akhir scope, saat mengatur ulang properti, saat menutup layar. Di lingkungan multi-thread ini bisa terjadi di antara dua baris kode. Selalu periksa weak melalui guard let atau if let.

Apa perbedaan weak dengan __weak di Objective-C?

Secara semantik identik: keduanya menyediakan zeroing weak. Perbedaan: Swift memerlukan tipe optional dan var, Objective-C menggunakan pengubah property. Objective-C juga mendukung __unsafe_unretained — referensi lemah tanpa zeroing (risiko dangling pointer).

Ringkasan

  • Weak Reference — referensi tidak memiliki yang tidak meningkatkan retain count dan secara otomatis menjadi nol saat dealokasi
  • Sintaksisweak var + tipe optional; hanya class-types dan protokol AnyObject
  • Zeroing weak — runtime meniadakan semua referensi weak ke objek yang dibebaskan, mencegah dangling pointer
  • Skenario — delegat, parent-child dengan umpan balik, closure asinkron ([weak self])
  • Weak vs Unowned — weak menjadi nol (aman), unowned tidak menjadi nol (risiko crash, tetapi non-optional)
  • Kinerja — weak lebih lambat dari strong karena lookup di tabel runtime; untuk jalur panas salin ke strong
  • Rekomendasi — jika tidak yakin tentang jaminan masa hidup — pilih weak

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