Weak Reference — mi ez, szintaxis és alkalmazása mobilfejlesztésben

Szerző: IT Sectr Megjelenés: 2026-03-30 Olvasási idő: 9 perc

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 Reference — olyan referencia, amely nem befolyásolja az objektum retain count-ját; az objektum felszabadulásakor nullázódik
  • Deklarációweak kulcsszó a var előtt; típus mindig opcionális (?)
  • Alkalmazás — delegáltak, closure-ök, parent-child kapcsolatok a retain cycle megszakításához
  • Biztonság — automatikus nil-re állítás az objektum felszabadítása után (zeroing weak)
  • Különbség az unowned-től — weak nullázódik és biztonságos, unowned nem nullázódik és élettartam-garanciát igényel

Mi az a Weak Reference?

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.

A weak szintaxisa Swiftben és Objective-C-ben

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.

Swift

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.

swift
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

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

Mikor alkalmazzunk gyenge referenciákat

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áltak (Delegate pattern)

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.

Parent-Child visszacsatolással

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.

Aszinkron closure-ök

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önyvWeakStrong
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.

Weak vs Unowned: összehasonlítás és forgatókönyvek

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.

Különbségek

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.

Mikor válassz weak-et

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.

Mikor válassz unowned-öt

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.

swift
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 weak referenciák korlátai és buktatói

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 weak teljesítménye

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.

A weak nem alkalmazható értéktípusokra

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.

A weak több szálon

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.

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

UIView és weak outlet

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

Mutathat-e weak referencia egy még létre nem hozott objektumra?

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.

Miért működik a weak csak class-típusokkal?

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.

Hogyan befolyásolja a weak a teljesítményt egy ciklusban?

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.

Mikor válhat a weak referencia váratlanul nil-lé?

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.

Miben különbözik a weak a __weak-től Objective-C-ben?

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 Reference — nem birtokló referencia, amely nem növeli a retain count-ot és automatikusan nullázódik felszabadításkor
  • Szintaxisweak var + optional típus; csak class-típusok és AnyObject protokollok
  • Zeroing weak — a runtime nullázza az összes weak referenciát a felszabadított objektumhoz, megelőzve a lógó mutatókat
  • Forgatókönyvek — delegáltak, parent-child visszacsatolással, aszinkron closure-ök ([weak self])
  • Weak vs Unowned — weak nullázódik (biztonságos), unowned nem nullázódik (crash kockázat, de non-optional)
  • Teljesítmény — weak lassabb a strong-nál a runtime táblában történő lookup miatt; forró útvonalakon másold strong-ba
  • Ajánlás — ha nem vagy biztos az élettartam-garanciákban — válassz weak-et

Kulcsraké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.

Projekt megbeszélése

Olvassa el is