ARC: vad är det, funktionsprincipen för Automatic Reference Counting i iOS

Författare: IT Sectr Publicerad: 2026-03-29 Lästid: 8 min

Automatic Reference Counting (ARC) — ett minneshanteringssystem i Swift och Objective-C som automatiskt räknar antalet referenser till varje objekt och frigör det när räknaren når noll. Enligt Apple Swift Documentation, 2026 är ARC inbäddat i kompilatorn och fungerar i kompileringsfasen, och infogar retain/release-anrop på rätt ställen. Till skillnad från Garbage Collection kräver ARC ingen separat insamlingstråd och skapar inga pauser under applikationens körning.

Huvudpunkter

  • ARC — Automatic Reference Counting, kompilatorbaserat minneshanteringssystem i Swift och Objective-C
  • Funktionsprincip — varje objekt har en referensräknare (retain count), vid nollställning frigörs objektet omedelbart
  • Kvalificerare — strong, weak och unowned bestämmer hur referensen påverkar räknaren och objektets livscykel
  • Skillnad från GC — ARC fungerar deterministiskt i kompileringsfasen, utan Stop-The-World-pauser och bakgrundsinsamlingstråd
  • Retain Cycle — ARC:s huvudproblem: om två objekt refererar till varandra via strong, når deras räknare aldrig noll

Vad är ARC?

ARC (Automatic Reference Counting) — är en mekanism för minneshantering på kompilatornivå, introducerad av Apple i Xcode 4.2 (2011) för Objective-C och ärvd av Swift. Till skillnad från manuell minneshantering (Manual Retain-Release, MRR) automatiserar ARC helt anropen retain, release och autorelease, och infogar dem i kompileringsfasen utan utvecklarens medverkan.

ARC är ingen garbage collector. Det är en statisk analys med dynamisk kodinfogning: kompilatorn analyserar objektens livslängd och placerar retain/release vid punkter där objekt skapas, kopieras eller lämnar omfattningen. Resultatet — deterministisk minnesfrigöring: objektet tas bort precis när det inte längre refereras, utan fördröjningar och pauser.

Enligt WWDC 2011 Session 323 minskade övergången från MRR till ARC antalet crash-buggar relaterade till minne med 70 % i Apples applikationer. Utvecklare slutade att manuellt balansera retain/release, vilket eliminerade en hel klass av läckor och double-free-fel.

Hur fungerar Automatic Reference Counting

Varje objekt i minnet har en referensräknare (retain count). När ett objekt skapas sätts räknaren till 1. När en ny strong-referens pekar på objektet ökar räknaren (retain). När strong-referensen försvinner minskar räknaren (release). Vid noll frigörs objektet omedelbart.

Swift-kompilatorn infogar inte retain/release vid varje tilldelning — den använder statisk analys för optimering. Till exempel, om ett objekt garanterat inte används efter överföring, kan kompilatorn hoppa över onödig release/retain. Denna optimering kallas ARC Optimisation.

swift
class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) initierad (retain count: 1)")
    }
    deinit {
        print("\(name) frigjord")
    }
}

func testARC() {
    let p = Person(name: "Alice")  // retain count = 1
    let q = p                      // retain count = 2
    // q lämnar omfattningen
    // retain count = 1
    // p lämnar omfattningen
    // retain count = 0 → deinit
}

I detta exempel syns hur ARC hanterar räknaren: vid tilldelningen q = p ökar räknaren, när q lämnar omfattningen minskar den. När den sista strong-referensen försvinner anropas deinitialiseraren omedelbart. Ingen garbage collector väntar — minnet frigörs direkt.

ARC vs Garbage Collection: viktigaste skillnaderna

ARC och Garbage Collection löser samma uppgift — automatisk minneshantering — men med fundamentalt olika angreppssätt. Valet mellan dem bestämmer språkets arkitektur: Swift (ARC) vs Java/Go (GC). Låt oss titta på huvudskillnaderna.

EgenskapARC (Swift/ObjC)GC (Java/Go)
FrigöringstillfälleDeterministiskt: omedelbart vid räknarens nollställningIcke-deterministiskt: vid nästa insamling
ExekveringspauserInga (retain/release-infogningar i kompileringsfasen)Stop-The-World-pauser förekommer (2–200 ms)
OverheadÖkning/minskning av räknare vid varje referensGenomgång av objektgraf, markering, frigöring
ProblemRetain Cycle (manuell lösning)Heap-fragmentering, läckor vid glömda referenser
Extra trådKrävs inteKräver garbage collector-tråd

Den viktigaste avvägningen: ARC ger förutsägbar objektlivslängd och noll pauser, men kräver att utvecklaren förstår retain cycle och väljer rätt weak/unowned. GC befriar från dessa bekymmer, men till priset av icke-deterministiska pauser och en extra tråd.

Strong, Weak och Unowned: referenskvalificerare i ARC

ARC definierar tre typer av referenskvalificerare, som var och en påverkar räknaren och objektets livscykel olika. Rätt val av kvalificerare är grunden för säkert arbete med minne i Swift.

Strong

Strong — standardkvalificeraren. Varje strong-referens ökar objektets retain count med 1. Så länge det finns minst en strong-referens lever objektet. Alla klassegenskaper och lokala variabler i Swift är som standard strong. Strong-referenser skapar en äganderelation: objekt A äger objekt B.

Weak

Weak — en referens som inte ökar retain count. Objektet kan frigöras även om en weak-referens pekar på det. Efter frigöring sätts weak-referensen automatiskt till nil. Weak-referenser deklareras alltid som var med en optionell typ (?). De används för att bryta retain cycle, särskilt i delegate-mönstret.

Unowned

Unowned — en icke-ägande referens som, liksom weak, inte ökar retain count. Emellertid sätts unowned-referensen inte till nil efter frigöring — åtkomst till ett frigjort objekt orsakar en krasch. Unowned används när det är garanterat att objektet lever minst lika länge som det refererande objektet. Typiskt scenario — closures och förälder-barn-relationer med garanterad livslängd.

swift
class Customer {
    let name: String
    var card: CreditCard?         // strong
    init(name: String) { self.name = name }
    deinit { print("\(name) frigjord") }
}

class CreditCard {
    let number: String
    unowned let customer: Customer   // unowned — äger inte
    init(number: String, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Kort \(number) frigjort") }
}

var customer: Customer? = Customer(name: "Bob")
customer?.card = CreditCard(number: "1234", customer: customer!)
customer = nil
// Customer och CreditCard båda frigjorda — ingen retain cycle

Här använder CreditCard en unowned-referens till Customer. Customer äger kortet (strong), och kortet äger inte kunden (unowned). När Customer blir nil frigörs båda objekten — ingen retain cycle uppstår. Om card.customer hade varit strong skulle cykeln ha blockerat frigöringen.

Typiska ARC-problem och deras lösningar

Trots automatiseringen är ARC inget universalmedel. Utvecklare stöter på flera typiska problem som kräver förståelse av den interna minneshanteringsmekanismen.

Retain Cycle i closures

Closures i Swift fångar externa variabler via strong-referens. Om en closure tilldelas en klassegenskap och fångar self — uppstår en retain cycle: klassen håller closuren, closuren håller self. Lösning — capture list med weak eller unowned.

swift
class NetworkManager {
    var completionHandler: ((Data?) -> Void)?
    var data: Data?

    func fetchData() {
        completionHandler = { [weak self] result in
            guard let self else { return }
            self.data = result
            self.processResult()
        }
    }

    func processResult() { }
}

Capture list [weak self] skapar en weak-referens till self inuti closuren. Detta bryter den potentiella retain cycle. Guard let self garanterar att objektet lever innan koden exekveras. weak self — standardpraxis för asynkrona closures i Swift.

Prestanda för retain/release

Även om retain/release är lätta operationer, orsakar frekventa ökningar/minskningar av räknaren i heta loopar overhead. I Swift 5.9+ använder kompilatorn optimering, där onödiga retain/release tas bort om analysatorn kan bevisa säkerhet. Men i Objective-C kan retain/release fortfarande vara en flaskhals i högbelastningsscenarier med miljontals anrop per sekund.

Autorelease Pool

Autorelease Pool — en mekanism för fördröjd release, som används i Objective-C och vissa Swift-scenarier. Objekt placeras i en pool och får release när poolen töms. I loopar med många temporära objekt (t.ex. JSON-tolkning) minskar skapandet av en egen autoreleasepool toppförbrukningen av arbetsminne.

Vanliga frågor

Hur skiljer sig ARC från manuell minneshantering (MRR)?

Vid manuell hantering (MRR) anropade utvecklaren explicit retain, release och autorelease. ARC infogar dessa anrop automatiskt i kompileringsfasen, vilket eliminerar risken för double-free, läckor på grund av glömd release och fel i retain/release-balansering.

Kan ARC arbeta med C/C++-kod?

ARC hanterar endast Objective-C-objekt och Swift-klasser. För C/C++-strukturer och pekare tillämpas inte ARC — dessa objekt hanteras manuellt eller via C++ smarta pekare (shared_ptr, unique_ptr). Core Foundation-objekt (CFString, CGColor) omfattas inte heller av ARC.

När ska man använda weak och när unowned?

weak — när objektet kan frigöras före det refererande objektet (delegater, asynkrona closures). unowned — när det är garanterat att objektet lever minst lika länge som det refererande objektet (förälder-barn, där barnet inte kan existera utan föräldern). Om du är osäker — välj weak.

Vad är existentiella typer och hur påverkar de ARC?

Existentiella typer (protocol as type) i Swift packar värdet i en speciell behållare (existential container). Detta ökar antalet retain/release vid protokollgränser. I Swift 5.7+ minskar opaque result types och some-parametrar overhead genom att eliminera behållaren.

Hur kontrollerar jag retain count i Swift?

Det finns inget direkt API för att läsa retain count i Swift — detta anses vara en implementeringsdetalj. För diagnostik, använd Instruments (Allocations, Leaks) eller Memory Debugger i Xcode. Dessa verktyg visar antalet levande instanser av klassen och retentionskedjor.

Sammanfattning

  • ARC — kompilatorbaserat minneshanteringssystem för Swift och Objective-C som fungerar via referensräkning
  • Princip — varje objekt har retain count; vid noll frigörs objektet omedelbart och deterministiskt
  • Skillnad från GC — ARC fungerar utan bakgrundstråd och Stop-The-World-pauser, men kräver kontroll av retain cycle
  • Strong — ökar räknaren; weak och unowned — ökar inte, men unowned nollställs inte vid frigöring
  • Closures — huvudorsaken till retain cycle i Swift; capture list [weak self] — standardlösningen
  • Autorelease Pool — mekanism för fördröjd frigöring av temporära objekt i loopar och anpassade scenarier
  • Diagnostik — Xcode Memory Debugger, Instruments och LeakCanary (via ObjC bridge) för att hitta problem

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å