Weak Reference (gyenge referencia) — olyan hivatkozás egy objektumra, amely nem növeli annak retenciós számlálóját az ARC-ben. Az Apple Swift Language Guide, 2026 szerint a weak referenciák a weak kulcsszóval deklarálhatók, és mindig opcionális típusúak. Amikor az objektum felszabadul, az összes weak referencia automatikusan nil-re állítódik, ami megakadályozza a lógó mutatókat, és a gyenge referenciákat biztonságos mechanizmussá teszi a retain cycle megszakításához.
Főbb pontok
weak kulcsszó a var előtt; típus mindig opcionális (?)Weak Reference — egy nem birtokló hivatkozás egy objektumra az ARC-ben (Automatic Reference Counting). Ellentétben a strong referenciával, amely növeli az objektum retain count-ját és garantálja annak életét, a weak referencia lehetővé teszi az objektum felszabadítását még akkor is, ha még hivatkoznak rá. Felszabadítás után a weak referencia automatikusan nil-re állítódik — ezt hívják zeroing weak-nek.
A zeroing weak a Swift és Objective-C runtime kulcsfontosságú jellemzője. Amikor az objektum referenciaszámlálója eléri a nullát és az objektum felszabadul, a runtime végigjárja az összes weak referenciát ehhez az objektumhoz (amelyek egy speciális weak táblában vannak tárolva), és nil-re állítja őket. Ez garantálja, hogy a felszabadított memóriához való hozzáférés (use-after-free) lehetetlen a weak referenciákon keresztül — bármely olvasás nil-t ad vissza.
Az Apple WWDC 2012 Session 406 szerint a zeroing weak referenciák megszüntették a lógó mutatókkal (dangling pointers) kapcsolatos crash hibák egész osztályát, amelyek elterjedtek voltak a kézi memóriakezelésben (MRR). Az MRR-ben a gyenge referenciák csak __unsafe_unretained formában léteztek — nem nullázódtak, és a felszabadított objektumhoz való hozzáférés EXC_BAD_ACCESS-hez vezetett.
Nézzük meg a weak referenciák deklarálásának szintaxisát az Apple ökoszisztéma mindkét nyelvében. A közös runtime ellenére a szintaxis eltérő, de a szemantika azonos.
Swiftben a weak referenciák a weak kulcsszóval deklarálhatók a var előtt. A típusnak mindig opcionálisnak kell lennie (Type?), mivel a referencia bármikor nullázódhat. A konstansok (let) nem lehetnek weak — csak változók.
class ViewController: UIViewController {
// weak-tulajdonságok: csak var, csak optional
weak var delegate: ViewControllerDelegate?
weak var parentView: UIView?
weak var completionHandler: ((Bool) -> Void)? // ⚠️ closure-ök nem tárolnak weak-et
// ⬆️ Hiba: weak csak class-típusokra alkalmazható, nem closure-re
}
Fontos: a weak csak osztálypéldányokra (class-types), AnyObject-re és az AnyObject-től örökölt protokollokra alkalmazható. A struct, enum és closure nem lehet weak — ezek értéktípusok és nem vesznek részt az ARC-ben.
Objective-C-ben a weak tulajdonságok a __weak attribútummal vagy a weak módosítóval deklarálhatók a property-ben:
// Objective-C: weak property
@interface MyViewController : UIViewController
@property (weak, nonatomic) id<MyDelegate> delegate;
@end
// Lokális weak-változó
__weak MyObject *weakRef = someStrongObject;
Az Objective-C runtime szintén biztosítja a zeroing weak-et, de emellett blokkolja a weak használatát C-struktúrákkal és néhány Core Foundation objektummal. Ezekre a __unsafe_unretained alkalmazandó — zeroing nélkül.
A gyenge referenciák — nem univerzális megoldás, hanem eszköz konkrét forgatókönyvekhez. A weak mindenhol való használata túlzott komplexitáshoz vezet és rontja az olvashatóságot. Tekintsük át a helyes alkalmazási forgatókönyveket.
Delegált — a fő forgatókönyv a weak számára. A tulajdonos objektum (pl. UITableView) strong referenciát tart magán, a delegált (UIViewController) pedig nem birtokolhatja a táblázatot. Az Apple SDK garantálja, hogy minden delegate és dataSource weak. Saját protokollokhoz mindig használj weak var delegate-et.
Amikor a gyermek objektumnak hivatkoznia kell a szülőre (pl. ChildViewController a koordinátor eléréséhez), használj weak referenciát. A szülő birtokolja a gyermeket (strong), a gyermek megfigyeli a szülőt (weak) — retain cycle kizárva.
Capture list [weak self] — a retain cycle elkerülésének szabványos módja a closure-ökben, amelyek osztály tulajdonságaiként vannak tárolva. Ha a self felszabadulhat a closure befejeződése előtt — weak self kötelező.
| Forgatókönyv | Weak | Strong |
|---|---|---|
| Delegate | ✅ Mindig weak | ❌ Retain cycle |
| Parent → Child | ❌ Nem szükséges (szülőnek birtokolnia kell) | ✅ Strong |
| Child → Parent | ✅ Weak | ❌ Retain cycle |
| Aszinkron callback | ✅ [weak self] | ❌ Retain cycle kockázat |
| Erős kapcsolat (owned) | ❌ unowned | ✅ Strong |
Általános szabály: ha A objektum birtokolja B-t (A → B strong), akkor B → A-nak weak-nek vagy unowned-nek kell lennie. A strong referenciák irányának mindig a tulajdonostól az alárendelt felé kell mutatnia.
Mind a weak, mind az unowned nem növeli a retain count-ot, de viselkedésük eltér az objektum felszabadítása után. A köztük való választás élettartam-garanciák kérdése.
Weak: automatikusan nullázódik (nil), típus mindig optional, unwrap-et igényel használat előtt. Biztonságos — a nil elérése nem okoz crash-t.
Unowned: nem nullázódik, típus non-optional. Ha az objektum felszabadult, az unowned referencia lógó mutatóvá válik — elérése runtime crash-t okoz. Az unowned feltételezi, hogy az objektum nem él rövidebb ideig, mint a hivatkozó fél.
Weak-et válassz, ha: az objektum bármikor felszabadulhat (delegált a képernyő bezárása után), nem irányítod az objektum élettartamát, vagy kétségeid vannak a garanciákról. Weak — univerzális biztonságos választás.
Unowned-öt válassz, ha: az objektum garantáltan nem szabadulhat fel a hivatkozó előtt (pl. Customer → CreditCard, ahol a kártya nem létezik ügyfél nélkül). Az unowned non-optional API-t ad unwrap nélkül, ami kényelmesebb a kódban.
class Order {
let id: Int
var items: [Item] = []
init(id: Int) { self.id = id }
// Erős kapcsolat: Order birtokolja Item-et
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 nem él Order nélkül
init(name: String, order: Order) {
self.name = name
self.order = order
}
}
// Példa weak-kel: delegált élettartam-garancia nélkül
protocol NetworkServiceDelegate: AnyObject {
func didReceiveResponse(data: Data)
}
class NetworkService {
weak var delegate: NetworkServiceDelegate? // ✅ weak — delegált elmehet
}
A példában az Item unowned-öt használ, mert a rendelési elem nem létezhet maga a rendelés nélkül — az élettartam-garancia sziklaszilárd. A NetworkService weak-et használ, mert a delegált (pl. ViewController) bármikor bezárható és felszabadítható.
A gyenge referenciák — hatékony eszköz, de vannak korlátaik, amelyeket fontos megérteni az iOS-fejlesztésben való helyes alkalmazáshoz.
A gyenge referenciák lassabbak a strong-nál: minden eléréskor a runtime ellenőrzi, hogy az objektum felszabadult-e (lookup a weak táblában). Az esetek túlnyomó többségében a különbség észrevehetetlen, de forró ciklusokban milliós eléréssel a weak szűk keresztmetszet lehet. Magas terhelésű forgatókönyvekhez használj strong-ot és rendezd át az architektúrát.
Struct, enum, tuple — értéktípusok, amelyek nem vesznek részt az ARC-ben. A weak struct deklarálásának kísérlete fordítási hibához vezet. Értéktípusra mutató gyenge referencia tárolásához használj wrappert class-típusban vagy closure-t.
Zeroing weak thread-safe: ha az objektum egy szálon felszabadul, a weak referencia minden szálon atomi módon nullázódik. Azonban a weak referencia olvasása és használata közötti rés versenyhelyzethez vezethet — az objektum felszabadul a weak referencia megszerzése és használata között. Megoldás: a gyenge referencia strong-befogása egy lokális változóba.
// Versenyhelyzet weak-kel több szálon
func performAsync() {
weak var weakSelf = self
queue.async {
// ⚠️ weakSelf nil lehet az ellenőrzés és használat között
if weakSelf != nil {
weakSelf!.doSomething() // CRASH ha nil lett
}
}
}
// ✅ Javítás: erős befogás a használat idejére
func performAsyncSafe() {
queue.async { [weak self] in
guard let strongSelf = self else { return }
strongSelf.doSomething() // strongSelf — lokális strong referencia
}
}
A biztonságos változatban a weak self befogásra kerül, majd azonnal egy lokális strong változóba, strongSelf-be lesz kicsomagolva. Ha a self még él — életben marad a blokk végrehajtásának idejére. Ha nem — a guard aktiválódik és a kód nem hajtódik végre. Ez az idioma — a szabványos minta aszinkron closure-ökhöz Swiftben.
IBOutlet-nek az Interface Builder-ben weak-nek kell lennie, mivel a nézet hierarchia már tart egy strong referenciát a subview-ra. A strong referencia megkettőzése a vezérlőben nem hoz létre retain cycle-t, de felesleges. A gyenge referencia az outlet-re — Apple ajánlás, bár sok fejlesztő strong-ot használ a kód egyszerűsítése érdekében.
Gyakran Ismételt Kérdések
Nem, a weak csak létező objektumra vagy nil-re mutathat. Új objektum létrehozásakor először egy strong referenciát kapsz (az inicializátoron keresztül), és csak azután rendelhetsz hozzá gyenge referenciát. A weak nil kezdetben — normális állapot.
A Weak az ARC-en alapul, amely csak referenciatípusokat (osztályokat) kezel. Az értéktípusok (struct, enum) hozzárendeléskor másolódnak és nincs retain count-juk. Értéktípusok gyenge kapcsolódásához használj closure-öket vagy wrapper-t class-ben weak tulajdonsággal.
Minden weak referencia eléréskor a runtime egy lookup-ot hajt végre a táblájában. Egy milliós iterációjú ciklusban ez 2–5-ször lassabb lehet, mint a strong referencia. Forró útvonalak esetén másold a weak-et egy lokális strong változóba a ciklus előtt.
Amikor az objektumra mutató összes strong referencia elvész — a hatókör végén, tulajdonság visszaállításakor, képernyő bezárásakor. Többszálas környezetben ez két kódsor között is megtörténhet. Mindig ellenőrizd a weak-et guard let vagy if let segítségével.
Szemantikailag azonos: mindkettő zeroing weak-et biztosít. Különbségek: a Swift optional típust és var-t igényel, az Objective-C a property módosítóját használja. Az Objective-C emellett támogatja a __unsafe_unretained-et — gyenge referenciát zeroing nélkül (lógó mutató veszélye).
Összefoglaló
weak var + optional típus; csak class-típusok és AnyObject protokollokKulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is