Weak Reference (zəif istinad) — ARC-də obyektin saxlama sayğacını artırmayan istinaddır. Apple Swift Language Guide, 2026-ya görə, weak-istinadlar weak açar sözü ilə elan edilir və həmişə opsional tipə malikdir. Obyekt sərbəst buraxıldıqda, ona olan bütün weak-istinadlar avtomatik olaraq nil-ə təyin edilir ki, bu da asılı göstəricilərin qarşısını alır və zəif istinadları retain cycle-ı qırmaq üçün təhlükəsiz mexanizm edir.
Əsas
weak açar sözü; tip həmişə opsionaldır (?)Weak Reference — ARC-də (Automatic Reference Counting) obyektə sahib olmayan istinaddır. Obyektin retain count-nı artıran və onun həyatını qarantiyalayan strong-istinaddan fərqli olaraq, weak-istinad obyektin hələ də istinadlar olsa belə sərbəst buraxılmasına imkan verir. Sərbəst buraxıldıqdan sonra weak-istinad avtomatik olaraq nil-ə təyin edilir — bu zeroing weak adlanır.
Zeroing weak — Swift və Objective-C runtime-ının əsas xüsusiyyətidir. Obyektin istinad sayğacı sıfıra çatdıqda və obyekt deallokasiya edildikdə, runtime bu obyektə olan bütün weak-istinadları (xüsusi weak-cədvəlində saxlanılır) gəzir və onları nil-ə təyin edir. Bu, weak-istinadlar vasitəsilə sərbəst buraxılmış yaddaşa müraciətin (use-after-free) qeyri-mümkün olmasını təmin edir — istənilən oxuma nil qaytarır.
Apple WWDC 2012 Session 406-ya görə, zeroing weak istinadlar əl ilə yaddaş idarəçiliyində (MRR) geniş yayılmış asılı göstəricilərlə (dangling pointers) bağlı crash səhvlərinin bütün sinfini aradan qaldırdı. MRR-də zəif istinadlar yalnız __unsafe_unretained kimi mövcud idi — onlar sıfırlanmırdı və sərbəst buraxılmış obyektə müraciət EXC_BAD_ACCESS-ə səbəb olurdu.
Apple ekosisteminin hər iki dilində weak-istinadların elan sintaksisinə baxaq. Ümumi runtime-a baxmayaraq, sintaksis fərqlənir, lakin semantika eynidir.
Swift-də weak-istinadlar var qabağında weak açar sözü ilə elan edilir. Tip həmişə opsional olmalıdır (Type?), çünki istinad istənilən anda sıfırlana bilər. Sabitlər (let) weak ola bilməz — yalnız dəyişənlər.
class ViewController: UIViewController {
// weak-xüsusiyyətlər: yalnız var, yalnız optional
weak var delegate: ViewControllerDelegate?
weak var parentView: UIView?
weak var completionHandler: ((Bool) -> Void)? // ⚠️ closure-lar weak saxlamır
// ⬆️ Xəta: weak yalnız class-tipi üçün tətbiq edilə bilər, closure üçün deyil
}
Vacib: weak yalnız sinif nümunələrinə (class-types), AnyObject-ə və AnyObject-dən miras alan protokollara tətbiq oluna bilər. Struct, enum və closure weak ola bilməz — onlar dəyər tipləridir və ARC-də iştirak etmirlər.
Objective-C-də weak-xüsusiyyətlər __weak atributu və ya property-də weak modifikatoru ilə elan edilir:
// Objective-C: weak property
@interface MyViewController : UIViewController
@property (weak, nonatomic) id<MyDelegate> delegate;
@end
// Lokal weak-dəyişən
__weak MyObject *weakRef = someStrongObject;
Objective-C runtime da zeroing weak təmin edir, lakin əlavə olaraq weak-in C-strukturları və bəzi Core Foundation obyektləri ilə istifadəsini bloklayır. Onlar üçün __unsafe_unretained tətbiq edilir — zeroing olmadan.
Zəif istinadlar — universal həll deyil, konkret ssenarilər üçün alətdir. Hər yerdə weak istifadə etmək həddindən artıq mürəkkəbliyə gətirib çıxarır və oxunaqlılığı pisləşdirir. Düzgün tətbiq ssenarilərinə baxaq.
Delegat — weak üçün əsas ssenari. Sahib-obyekt (məsələn, UITableView) özündə strong-istinad saxlayır, delegat (UIViewController) isə cədvələ sahib olmamalıdır. Apple SDK bütün delegate və dataSource-ların weak olmasını təmin edir. Öz protokollarınız üçün həmişə weak var delegate istifadə edin.
Uşaq obyekt valideynə istinad etməli olduqda (məsələn, ChildViewController koordinatora giriş üçün), weak-istinaddan istifadə edin. Valideyn uşağa sahibdir (strong), uşaq valideyni müşahidə edir (weak) — retain cycle istisna edilir.
Capture list [weak self] — sinifin xüsusiyyətləri kimi saxlanılan closure-larda retain cycle-dan qaçmağın standart üsuludur. Əgər self closure tamamlanmazdan əvvəl sərbəst buraxıla bilərsə — weak self məcburidir.
| Ssenari | Weak | Strong |
|---|---|---|
| Delegate | ✅ Həmişə weak | ❌ Retain cycle |
| Parent → Child | ❌ Lazım deyil (valideyn sahib olmalıdır) | ✅ Strong |
| Child → Parent | ✅ Weak | ❌ Retain cycle |
| Asinxron callback | ✅ [weak self] | ❌ Retain cycle riski |
| Güclü əlaqə (owned) | ❌ unowned | ✅ Strong |
Ümumi qayda: əgər A obyekti B-yə sahibdirsə (A → B strong), onda B → A weak və ya unowned olmalıdır. Strong-istinadların istiqaməti həmişə sahibdən tabe olana doğru olmalıdır.
Həm weak, həm də unowned retain count-nı artırmır, lakin obyektin deallokasiyasından sonra davranışları fərqlənir. Onlar arasında seçim ömür qarantiyaları məsələsidir.
Weak: avtomatik sıfırlanır (nil), tip həmişə optionaldır, istifadədən əvvəl unwrap tələb edir. Təhlükəsizdir — nil-ə müraciət crash-a səbəb olmur.
Unowned: sıfırlanmır, tip non-optionaldır. Əgər obyekt sərbəst buraxılıbsa, unowned-istinad asılı göstəriciyə çevrilir — ona müraciət runtime crash-na səbəb olur. Unowned obyektin istinad edən tərəfdən az yaşamadığını qəbul edir.
Weak seçin, əgər: obyekt istənilən anda deallokasiya edilə bilərsə (ekran bağlandıqdan sonra delegat), obyektin ömrünü idarə etmirsinizsə və ya qarantiyalara şübhə edirsinizsə. Weak — universal təhlükəsiz seçimdir.
Unowned seçin, əgər: obyekt qarantiyalı olaraq istinad edəndən əvvəl sərbəst buraxıla bilməz (məsələn, Customer → CreditCard, burada kart müştərisiz mövcud deyil). Unowned unwrap olmadan non-optional API verir ki, bu da kodda daha rahatdır.
class Order {
let id: Int
var items: [Item] = []
init(id: Int) { self.id = id }
// Güclü əlaqə: Order Item-ə sahibdir
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 Order olmadan yaşamır
init(name: String, order: Order) {
self.name = name
self.order = order
}
}
// Weak ilə nümunə: ömür qarantiyası olmayan delegat
protocol NetworkServiceDelegate: AnyObject {
func didReceiveResponse(data: Data)
}
class NetworkService {
weak var delegate: NetworkServiceDelegate? // ✅ weak — delegat gedə bilər
}
Nümunədə Item unowned istifadə edir, çünki sifariş elementi sifarişin özü olmadan mövcud ola bilməz — ömür qarantiyası dəmir-betondur. NetworkService weak istifadə edir, çünki delegat (məsələn, ViewController) istənilən anda bağlana və sərbəst buraxıla bilər.
Zəif istinadlar — güclü alətdir, lakin iOS inkişafında düzgün tətbiq üçün başa düşülməsi vacib olan məhdudiyyətləri var.
Zəif istinadlar strong-dan yavaşdır: hər girişdə runtime obyektin sərbəst buraxılıb-buraxılmadığını yoxlayır (weak-cədvəlində lookup). Ssenarilərin böyük əksəriyyətində fərq hiss olunmur, lakin milyonlarla müraciəti olan isti dövrələrdə weak darboğaz ola bilər. Yüksək yüklü ssenarilər üçün strong istifadə edin və arxitekturanı yenidən təşkil edin.
Struct, enum, tuple — ARC-də iştirak etməyən dəyər tipləridir. Weak struct elan etmək cəhdi kompilasiya xətasına səbəb olur. Dəyər tipinə zəif istinad saxlamaq üçün class tipində qablaşdırma və ya closure istifadə edin.
Zeroing weak ip-saxlayıcıdır: əgər obyekt bir ipdə sərbəst buraxılırsa, weak-istinad bütün iplərdə atomik olaraq sıfırlanır. Lakin weak-istinadın oxunması ilə ondan istifadə arasındakı fasilə yarış vəziyyətinə səbəb ola bilər — obyekt weak-istinadın alınması ilə istifadəsi arasında sərbəst buraxılır. Həll yolu: zəif istinadın strong-tutulması lokal dəyişənə.
// Weak ilə çoxiplikdə race condition
func performAsync() {
weak var weakSelf = self
queue.async {
// ⚠️ weakSelf yoxlama və istifadə arasında nil ola bilər
if weakSelf != nil {
weakSelf!.doSomething() // CRASH əgər nil oldusa
}
}
}
// ✅ Düzəliş: istifadə müddətinə güclü tutma
func performAsyncSafe() {
queue.async { [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething() // strongSelf — lokal strong-istinad
}
}
Təhlükəsiz variantda weak self tutulur, sonra dərhal lokal strong-dəyişənə strongSelf açılır. Əgər self hələ də yaşayırsa — blokun icrası müddətində yaşamağa davam edəcək. Əgər yoxsa — guard işə düşür və kod icra olunmur. Bu idiom — Swift-də asinxron closure-lar üçün standart nümunədir.
IBOutlet Interface Builder-də weak olmalıdır, çünki görünüş hiyerarxiyası artıq subview-da strong-istinad saxlayır. Kontrollerdə strong-istinadın təkrarlanması retain cycle yaratmır, lakin artıqdır. Outlet-ə zəif istinad — Apple tövsiyəsidir, baxmayaraq ki, bir çox proqramçı kodu sadələşdirmək üçün strong istifadə edir.
Tez-tez verilən suallar
Xeyr, weak yalnız mövcud obyektə və ya nil-ə işarə edə bilər. Yeni obyekt yaratdıqda əvvəlcə strong-istinad alırsınız (inicializator vasitəsilə), və yalnız bundan sonra zəif istinad təyin edə bilərsiniz. Əvvəldə weak nil — normal haldır.
Weak yalnız referans tiplərini (siniflər) idarə edən ARC-ə əsaslanır. Dəyər tipləri (struct, enum) təyin edilərkən kopyalanır və retain count-a malik deyil. Dəyər tiplərinin zəif əlaqəsi üçün closure-lar və ya weak-xüsusiyyətli class qablaşdırmasından istifadə edin.
Weak-istinada hər giriş runtime-cədvəlində lookup yerinə yetirir. Milyonlarla iterasiyası olan dövrədə bu strong-istinaddan 2–5 dəfə yavaş ola bilər. İsti yollar üçün weak-i dövrədən əvvəl lokal strong-dəyişənə kopyalayın.
Obyektə olan bütün strong-istinadlar itirildikdə — skopun sonunda, xüsusiyyət yenidən təyin edilərkən, ekran bağlandıqda. Çoxiplik mühitində bu iki kod sətri arasında baş verə bilər. Həmişə weak-i guard let və ya if let vasitəsilə yoxlayın.
Semantik olaraq eynidir: hər ikisi zeroing weak təmin edir. Fərqlər: Swift optional-tip və var tələb edir, Objective-C property modifikatorundan istifadə edir. Objective-C həmçinin __unsafe_unretained-i dəstəkləyir — zeroing olmadan zəif istinad (asılı göstərici riski).
Nəticə
weak var + opsional tip; yalnız class-tipləri və AnyObject protokollarıAçar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun