Weak Reference — wat het is, syntaxis en toepassing in mobiele ontwikkeling

Auteur: IT Sectr Gepubliceerd: 2026-03-30 Leestijd: 9 min

Weak Reference (zwakke referentie) — is een verwijzing naar een object die de retentieteller in ARC niet verhoogt. Volgens Apple Swift Language Guide, 2026 worden weak-referenties gedeclareerd met het sleutelwoord weak en hebben ze altijd een optioneel type. Wanneer het object wordt vrijgegeven, worden alle weak-referenties ernaar automatisch op nil gezet, wat dangling pointers voorkomt en zwakke referenties een veilig mechanisme maakt voor het verbreken van retain cycles.

Belangrijkste

  • Weak Reference — referentie die de retain count van een object niet beïnvloedt; wordt bij vrijgave van het object op nul gezet
  • Declaratie — sleutelwoord weak voor var; type altijd optioneel (?)
  • Toepassing — delegaten, closures, parent-child relaties voor het verbreken van retain cycles
  • Veiligheid — automatische instelling op nil na deallocatie van het object (zeroing weak)
  • Verschil met unowned — weak wordt op nul gezet en is veilig, unowned wordt niet op nul gezet en vereist levensduurgarantie

Wat is een Weak Reference?

Weak Reference — is een niet-bezittende verwijzing naar een object in ARC (Automatic Reference Counting). In tegenstelling tot een strong-referentie, die de retain count van een object verhoogt en het leven garandeert, staat een weak-referentie toe dat het object wordt vrijgegeven, zelfs als er nog naar wordt verwezen. Na vrijgave wordt de weak-referentie automatisch op nil gezet — dit heet zeroing weak.

Zeroing weak — een belangrijk kenmerk van de Swift en Objective-C runtime. Wanneer de referentieteller van een object nul bereikt en het object wordt gedealloceerd, doorloopt de runtime alle weak-referenties naar dit object (opgeslagen in een speciale weak-tabel) en zet ze op nil. Dit garandeert dat toegang tot vrijgegeven geheugen (use-after-free) onmogelijk is via weak-referenties — elke lezing retourneert nil.

Volgens Apple WWDC 2012 Session 406 hebben zeroing weak-referenties een hele klasse crash-bugs gerelateerd aan dangling pointers geëlimineerd, die wijdverbreid waren in handmatig geheugenbeheer (MRR). In MRR bestonden zwakke referenties alleen als __unsafe_unretained — ze werden niet op nul gezet en toegang tot een vrijgegeven object leidde tot EXC_BAD_ACCESS.

Syntaxis van weak in Swift en Objective-C

Laten we de syntaxis van het declareren van weak-referenties in beide talen van het Apple-ecosysteem bekijken. Ondanks de gedeelde runtime verschilt de syntaxis, maar de semantiek is identiek.

Swift

In Swift worden weak-referenties gedeclareerd met het sleutelwoord weak voor var. Het type moet altijd optioneel zijn (Type?), omdat de referentie op elk moment op nul kan worden gezet. Constanten (let) kunnen niet weak zijn — alleen variabelen.

swift
class ViewController: UIViewController {
    // weak-eigenschappen: alleen var, alleen optional
    weak var delegate: ViewControllerDelegate?
    weak var parentView: UIView?

    weak var completionHandler: ((Bool) -> Void)?  // ⚠️ closures slaan weak niet op
    // ⬆️ Fout: weak kan alleen worden toegepast op class-types, niet op closure
}

Belangrijk: weak is alleen van toepassing op klasse-instanties (class-types), AnyObject en protocollen die overerven van AnyObject. Struct, enum en closure kunnen niet weak zijn — het zijn waardetypen en nemen niet deel aan ARC.

Objective-C

In Objective-C worden weak-eigenschappen gedeclareerd via het attribuut __weak of de modifier weak in de property:

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

// Lokale weak-variabele
__weak MyObject *weakRef = someStrongObject;

De Objective-C runtime biedt ook zeroing weak, maar blokkeert daarnaast het gebruik van weak met C-structuren en sommige Core Foundation-objecten. Daarvoor wordt __unsafe_unretained gebruikt — zonder zeroing.

Wanneer zwakke referenties gebruiken

Zwakke referenties — geen universele oplossing, maar een hulpmiddel voor specifieke scenario's. Overal weak gebruiken leidt tot overmatige complexiteit en vermindert de leesbaarheid. Laten we de juiste toepassingsscenario's bekijken.

Delegaten (Delegate pattern)

Delegate — het belangrijkste scenario voor weak. Het eigenaar-object (bijv. UITableView) houdt een strong-referentie naar zichzelf vast, en de delegat (UIViewController) mag geen eigenaar van de tabel zijn. Apple SDK garandeert dat alle delegate en dataSource weak zijn. Gebruik voor eigen protocollen altijd weak var delegate.

Parent-Child met terugkoppeling

Wanneer een kind-object naar de ouder moet verwijzen (bijv. ChildViewController voor toegang tot de coördinator), gebruik dan een weak-referentie. De ouder is eigenaar van het kind (strong), het kind observeert de ouder (weak) — retain cycle uitgesloten.

Asynchrone closures

Capture list [weak self] — de standaardmanier om retain cycles te vermijden in closures die als eigenschappen van een klasse worden opgeslagen. Als self kan worden vrijgegeven voordat de closure is voltooid — is weak self verplicht.

ScenarioWeakStrong
Delegate✅ Altijd weak❌ Retain cycle
Parent → Child❌ Niet nodig (ouder moet eigenaar zijn)✅ Strong
Child → Parent✅ Weak❌ Retain cycle
Asynchrone callback✅ [weak self]❌ Risico op retain cycle
Sterke binding (owned)❌ unowned✅ Strong

Algemene regel: als object A eigenaar is van B (A → B strong), dan moet B → A weak of unowned zijn. De richting van strong-referenties moet altijd van eigenaar naar ondergeschikte zijn.

Weak vs Unowned: vergelijking en scenario's

Zowel weak als unowned verhogen de retain count niet, maar verschillen in gedrag na deallocatie van het object. De keuze ertussen is een kwestie van levensduurgaranties.

Verschillen

Weak: wordt automatisch op nul gezet (nil), type altijd optional, vereist unwrap voor gebruik. Veilig — toegang tot nil veroorzaakt geen crash.

Unowned: wordt niet op nul gezet, type non-optional. Als het object is vrijgegeven, wordt de unowned-referentie een dangling pointer — toegang ertoe veroorzaakt een runtime crash. Unowned veronderstelt dat het object niet korter leeft dan de verwijzende partij.

Wanneer weak kiezen

Weak kies als: het object op elk moment gedealloceerd kan worden (delegat na het sluiten van een scherm), je de levensduur van het object niet controleert of twijfelt aan de garanties. Weak — universele veilige keuze.

Wanneer unowned kiezen

Unowned kies als: het object gegarandeerd niet eerder kan worden vrijgegeven dan de verwijzende partij (bijv. Customer → CreditCard, waar de kaart niet bestaat zonder klant). Unowned geeft een non-optional API zonder unwrap, wat handiger is in code.

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

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

    // Sterke binding: Order is eigenaar van 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 leeft niet zonder Order

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

// Voorbeeld met weak: delegat zonder levensduurgarantie
protocol NetworkServiceDelegate: AnyObject {
    func didReceiveResponse(data: Data)
}

class NetworkService {
    weak var delegate: NetworkServiceDelegate?  // ✅ weak — delegat kan weggaan
}

In het voorbeeld gebruikt Item unowned, omdat een bestellingselement niet kan bestaan zonder de bestelling zelf — de levensduurgarantie is ijzersterk. NetworkService gebruikt weak, omdat de delegat (bijv. ViewController) op elk moment gesloten en vrijgegeven kan worden.

Beperkingen van weak-referenties en valkuilen

Zwakke referenties — een krachtig hulpmiddel, maar ze hebben beperkingen die belangrijk zijn om te begrijpen voor correct gebruik in iOS-ontwikkeling.

Prestaties van weak

Zwakke referenties zijn langzamer dan strong: bij elke toegang controleert de runtime of het object is vrijgegeven (lookup in de weak-tabel). In de overgrote meerderheid van scenario's is het verschil niet merkbaar, maar in hete lussen met miljoenen toegangen kan weak een knelpunt zijn. Gebruik voor scenario's met hoge belasting strong en reorganiseer de architectuur.

Weak is niet van toepassing op waardetypen

Struct, enum, tuple — waardetypen die niet deelnemen aan ARC. Een poging om weak struct te declareren leidt tot een compilatiefout. Gebruik voor het opslaan van een zwakke referentie naar een waardetype een wrapper in een class-type of een closure.

Weak in multithreading

Zeroing weak is thread-safe: als een object op één thread wordt vrijgegeven, wordt de weak-referentie op alle threads atomair op nul gezet. De tussenruimte tussen het lezen van een weak-referentie en het gebruik ervan kan echter leiden tot een raceconditie — het object wordt vrijgegeven tussen het verkrijgen van de weak-referentie en het gebruik ervan. Oplossing: strong-vastleggen van de zwakke referentie in een lokale variabele.

swift
// Raceconditie met weak in multithreading
func performAsync() {
    weak var weakSelf = self
    queue.async {
        // ⚠️ weakSelf kan nil zijn tussen controle en gebruik
        if weakSelf != nil {
            weakSelf!.doSomething()  // CRASH als het nil werd
        }
    }
}

// ✅ Oplossing: strong-vastleggen voor de duur van gebruik
func performAsyncSafe() {
    queue.async { [weak self] in
        guard let strongSelf = self else { return }
        strongSelf.doSomething()  // strongSelf — lokale strong-referentie
    }
}

In de veilige variant wordt weak self vastgelegd en vervolgens onmiddellijk uitgepakt in een lokale strong-variabele strongSelf. Als self nog leeft — blijft het leven tijdens de uitvoering van het blok. Zo niet — dan wordt guard geactiveerd en wordt de code niet uitgevoerd. Dit idiom — het standaard patroon voor asynchrone closures in Swift.

UIView en weak outlet

IBOutlet in Interface Builder moeten weak zijn, omdat de view-hiërarchie al een strong-referentie naar de subview heeft. Het dupliceren van een strong-referentie in de controller creëert geen retain cycle, maar is overbodig. Een zwakke referentie naar een outlet — aanbeveling van Apple, hoewel veel ontwikkelaars strong gebruiken voor eenvoudigere code.

Veelgestelde vragen

Kan een weak-referentie naar een object verwijzen dat nog niet is gemaakt?

Nee, weak kan alleen naar een bestaand object of nil verwijzen. Bij het maken van een nieuw object krijg je eerst een strong-referentie (via de initialisator), en pas daarna kun je een zwakke referentie toewijzen. weak nil aan het begin — een normale toestand.

Waarom werkt weak alleen met class-types?

Weak is gebaseerd op ARC, dat alleen referentietypen (klassen) beheert. Waardetypen (struct, enum) worden gekopieerd bij toewijzing en hebben geen retain count. Gebruik voor zwakke koppeling van waardetypen closures of wrappers in een class met een weak-eigenschap.

Hoe beïnvloedt weak de prestaties in een lus?

Elke toegang tot een weak-referentie voert een lookup uit in de runtime-tabel. In een lus met miljoenen iteraties kan dit 2–5 keer langzamer zijn dan een strong-referentie. Kopieer voor hete paden weak naar een lokale strong-variabele vóór de lus.

Wanneer kan een weak-referentie onverwacht nil worden?

Wanneer alle strong-referenties naar het object verloren gaan — aan het einde van de scope, bij het opnieuw instellen van een eigenschap, bij het sluiten van een scherm. In een multithreading-omgeving kan dit tussen twee regels code gebeuren. Controleer weak altijd via guard let of if let.

Wat is het verschil tussen weak en __weak in Objective-C?

Semantisch identiek: beide bieden zeroing weak. Verschillen: Swift vereist een optional-type en var, Objective-C gebruikt de property-modifier. Objective-C ondersteunt ook __unsafe_unretained — een zwakke referentie zonder zeroing (risico op dangling pointer).

Samenvatting

  • Weak Reference — niet-bezittende referentie die retain count niet verhoogt en automatisch wordt op nul gezet bij deallocatie
  • Syntaxisweak var + optional type; alleen class-types en AnyObject-protocollen
  • Zeroing weak — runtime zet alle weak-referenties naar een vrijgegeven object op nul, voorkomt dangling pointers
  • Scenario's — delegaten, parent-child met terugkoppeling, asynchrone closures ([weak self])
  • Weak vs Unowned — weak wordt op nul gezet (veilig), unowned wordt niet op nul gezet (crash risico, maar non-optional)
  • Prestaties — weak langzamer dan strong vanwege lookup in runtime-tabel; kopieer voor hete paden naar strong
  • Aanbeveling — als je niet zeker bent van levensduurgaranties — kies weak

We ontwikkelen een mobiele applicatie turnkey

IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.

Bespreek het project

Lees ook