Weak Reference — vad det är, syntax och tillämpning inom mobilutveckling

Författare: IT Sectr Publicerad: 2026-03-30 Lästid: 9 min

Weak Reference (svag referens) — är en referens till ett objekt som inte ökar dess referensräknare i ARC. Enligt Apple Swift Language Guide, 2026 deklareras weak-referenser med nyckelordet weak och har alltid en optionell typ. När objektet frigörs sätts alla weak-referenser till det automatiskt till nil, vilket förhindrar dinglande pekare och gör svaga referenser till en säker mekanism för att bryta retain cycles.

Huvudpunkter

  • Weak Reference — referens som inte påverkar objektets retain count; nollställs när objektet frigörs
  • Deklaration — nyckelordet weak före var; typ alltid optionell (?)
  • Användning — delegater, closures, parent-child-relationer för att bryta retain cycles
  • Säkerhet — automatisk inställning till nil efter objektets deallokering (zeroing weak)
  • Skillnad från unowned — weak nollställs och är säker, unowned nollställs inte och kräver livslängdsgaranti

Vad är en Weak Reference?

Weak Reference — är en icke-ägande referens till ett objekt i ARC (Automatic Reference Counting). Till skillnad från en strong-referens som ökar objektets retain count och garanterar dess livslängd, tillåter en weak-referens att objektet frigörs även om det fortfarande finns referenser till det. Efter frigöring sätts weak-referensen automatiskt till nil — detta kallas zeroing weak.

Zeroing weak — en nyckelfunktion i Swift och Objective-C runtime. När objektets referensräknare når noll och objektet deallokeras, går runtime igenom alla weak-referenser till detta objekt (lagrade i en speciell weak-tabell) och sätter dem till nil. Detta garanterar att åtkomst till frigjort minne (use-after-free) är omöjligt via weak-referenser — varje läsning returnerar nil.

Enligt Apple WWDC 2012 Session 406 eliminerade zeroing weak-referenser en hel klass av krascher relaterade till dinglande pekare (dangling pointers), som var vanliga i manuell minneshantering (MRR). I MRR fanns svaga referenser bara som __unsafe_unretained — de nollställdes inte och åtkomst till ett frigjort objekt ledde till EXC_BAD_ACCESS.

Syntax för weak i Swift och Objective-C

Låt oss titta på syntaxen för att deklarera weak-referenser i båda språken i Apples ekosystem. Trots gemensam runtime skiljer sig syntaxen, men semantiken är identisk.

Swift

I Swift deklareras weak-referenser med nyckelordet weak före var. Typen måste alltid vara optionell (Type?), eftersom referensen kan nollställas när som helst. Konstanter (let) kan inte vara weak — endast variabler.

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

    weak var completionHandler: ((Bool) -> Void)?  // ⚠️ closures lagrar inte weak
    // ⬆️ Fel: weak kan endast tillämpas på class-types, inte på closure
}

Viktigt: weak är endast tillämpligt på klassinstanser (class-types), AnyObject och protokoll som ärver från AnyObject. Struct, enum och closure kan inte vara weak — de är värdetyper och deltar inte i ARC.

Objective-C

I Objective-C deklareras weak-egenskaper via attributet __weak eller modifieraren weak i property:

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

// Lokal weak-variabel
__weak MyObject *weakRef = someStrongObject;

Objective-C runtime tillhandahåller också zeroing weak, men blockerar dessutom användningen av weak med C-strukturer och vissa Core Foundation-objekt. För dem används __unsafe_unretained — utan zeroing.

När man ska använda svaga referenser

Svaga referenser — inte en universallösning, utan ett verktyg för specifika scenarier. Att använda weak överallt leder till överdriven komplexitet och försämrar läsbarheten. Låt oss titta på rätt användningsscenarier.

Delegater (Delegate pattern)

Delegat — det främsta scenariot för weak. Ägarobjektet (t.ex. UITableView) håller en strong-referens till sig själv, och delegaten (UIViewController) bör inte äga tabellen. Apple SDK garanterar att alla delegate och dataSource är weak. För egna protokoll, använd alltid weak var delegate.

Parent-Child med återkoppling

När barnobjektet måste referera till föräldern (t.ex. ChildViewController för åtkomst till koordinatorn), använd en weak-referens. Föräldern äger barnet (strong), barnet observerar föräldern (weak) — retain cycle utesluten.

Asynkrona closures

Capture list [weak self] — standardsättet att undvika retain cycles i closures som lagras som klassegenskaper. Om self kan frigöras innan closure är klar — weak self är obligatoriskt.

ScenarioWeakStrong
Delegate✅ Alltid weak❌ Retain cycle
Parent → Child❌ Behövs inte (förälder bör äga)✅ Strong
Child → Parent✅ Weak❌ Retain cycle
Asynkron callback✅ [weak self]❌ Risk för retain cycle
Stark koppling (owned)❌ unowned✅ Strong

Generell regel: om objekt A äger B (A → B strong), då bör B → A vara weak eller unowned. Riktningen för strong-referenser bör alltid vara från ägaren till den underordnade.

Weak vs Unowned: jämförelse och scenarier

Både weak och unowned ökar inte retain count, men skiljer sig i beteende efter objektets deallokering. Valet mellan dem är en fråga om livslängdsgarantier.

Skillnader

Weak: nollställs automatiskt (nil), typ alltid optionell, kräver unwrap före användning. Säker — åtkomst till nil orsakar inte krasch.

Unowned: nollställs inte, typ non-optional. Om objektet har frigjorts blir unowned-referensen en dinglande pekare — åtkomst till den orsakar en runtime-krasch. Unowned förutsätter att objektet lever minst lika länge som den refererande parten.

När välja weak

Weak välj om: objektet kan deallokeras när som helst (delegat efter att skärmen stängts), du inte kontrollerar objektets livslängd, eller tvivlar på garantierna. Weak — universellt säkert val.

När välja unowned

Unowned välj om: objektet garanterat inte kan frigöras före den refererande (t.ex. Customer → CreditCard, där kortet inte finns utan kund). Unowned ger non-optional API utan unwrap, vilket är bekvämare i koden.

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

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

    // Stark koppling: Order äger 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 lever inte utan Order

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

// Exempel med weak: delegat utan livslängdsgaranti
protocol NetworkServiceDelegate: AnyObject {
    func didReceiveResponse(data: Data)
}

class NetworkService {
    weak var delegate: NetworkServiceDelegate?  // ✅ weak — delegat kan gå iväg
}

I exemplet använder Item unowned, eftersom ett orderelement inte kan existera utan själva ordern — livslängdsgarantin är järnhård. NetworkService använder weak, eftersom delegaten (t.ex. ViewController) kan stängas och frigöras när som helst.

Begränsningar för weak-referenser och fallgropar

Svaga referenser — ett kraftfullt verktyg, men de har begränsningar som är viktiga att förstå för korrekt användning inom iOS-utveckling.

Prestanda för weak

Svaga referenser är långsammare än strong: vid varje åtkomst kontrollerar runtime om objektet har frigjorts (lookup i weak-tabellen). I de allra flesta scenarier är skillnaden omärkbar, men i heta loopar med miljontals åtkomster kan weak vara en flaskhals. För scenarier med hög belastning, använd strong och omorganisera arkitekturen.

Weak gäller inte för värdetyper

Struct, enum, tuple — värdetyper som inte deltar i ARC. Försök att deklarera weak struct leder till kompileringsfel. För att lagra en svag referens till en värdetyp, använd en wrapper i class-type eller en closure.

Weak i flertrådad miljö

Zeroing weak är trådsäker: om objektet frigörs på en tråd nollställs weak-referensen på alla trådar atomärt. Dock kan intervallet mellan läsning av en weak-referens och användning leda till en race condition — objektet frigörs mellan att man får weak-referensen och använder den. Lösning: strong-infångning av den svaga referensen i en lokal variabel.

swift
// Race condition med weak i flertrådad miljö
func performAsync() {
    weak var weakSelf = self
    queue.async {
        // ⚠️ weakSelf kan vara nil mellan kontroll och användning
        if weakSelf != nil {
            weakSelf!.doSomething()  // KRASCH om den blev nil
        }
    }
}

// ✅ Fix: stark infångning för användningens varaktighet
func performAsyncSafe() {
    queue.async { [weak self] in
        guard let strongSelf = self else { return }
        strongSelf.doSomething()  // strongSelf — lokal strong-referens
    }
}

I den säkra varianten fångas weak self, packas sedan omedelbart upp i en lokal strong-variabel strongSelf. Om self fortfarande lever — förblir den vid liv under blockets exekvering. Om inte — guard aktiveras och koden körs inte. Detta idiom — standardmönstret för asynkrona closures i Swift.

UIView och weak outlet

IBOutlet i Interface Builder bör vara weak, eftersom vyns hierarki redan har en strong-referens till subview. Att duplicera strong-referensen i kontrollern skapar inte en retain cycle, men är överflödigt. Svag referens till outlet — Apples rekommendation, även om många utvecklare använder strong för att förenkla koden.

Vanliga frågor

Kan en weak-referens peka på ett objekt som ännu inte har skapats?

Nej, weak kan bara peka på ett befintligt objekt eller nil. När du skapar ett nytt objekt får du först en strong-referens (via initieraren), och först därefter kan du tilldela en svag referens. weak nil i början — ett normalt tillstånd.

Varför fungerar weak bara med class-types?

Weak är baserat på ARC som bara hanterar referenstyper (klasser). Värdetyper (struct, enum) kopieras vid tilldelning och har inget retain count. För svag koppling av värdetyper, använd closures eller en wrapper i en class med en weak-egenskap.

Hur påverkar weak prestandan i en loop?

Varje åtkomst till en weak-referens utför en lookup i runtime-tabellen. I en loop med miljontals iterationer kan detta vara 2–5 gånger långsammare än en strong-referens. För heta vägar, kopiera weak till en lokal strong-variabel före loopen.

När kan en weak-referens oväntat bli nil?

När alla strong-referenser till objektet förloras — i slutet av scopet, vid återställning av en egenskap, vid stängning av en skärm. I en flertrådad miljö kan detta hända mellan två kodrader. Kontrollera alltid weak via guard let eller if let.

Vad är skillnaden mellan weak och __weak i Objective-C?

Semantiskt identiskt: båda tillhandahåller zeroing weak. Skillnader: Swift kräver optionell typ och var, Objective-C använder property-modifieraren. Objective-C stöder också __unsafe_unretained — en svag referens utan zeroing (risk för dinglande pekare).

Sammanfattning

  • Weak Reference — icke-ägande referens som inte ökar retain count och automatiskt nollställs vid deallokering
  • Syntaxweak var + optionell typ; endast class-types och AnyObject-protokoll
  • Zeroing weak — runtime nollställer alla weak-referenser till frigjort objekt, förhindrar dinglande pekare
  • Scenarier — delegater, parent-child med återkoppling, asynkrona closures ([weak self])
  • Weak vs Unowned — weak nollställs (säker), unowned nollställs inte (kraschrisk, men non-optional)
  • Prestanda — weak långsammare än strong på grund av lookup i runtime-tabell; för heta vägar kopiera till strong
  • Rekommendation — om du inte är säker på livslängdsgarantier — välj weak

Vi utvecklar en mobil applikation nyckelfärdigt

IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.

Diskutera projektet

Läs också