ARC: co to je, princip fungování Automatic Reference Counting v iOS

Autor: IT Sectr Publikováno: 2026-03-29 Doba čtení: 8 min

Automatic Reference Counting (ARC) — systém správy paměti v Swift a Objective-C, který automaticky počítá počet referencí na každý objekt a uvolňuje jej, když počítadlo dosáhne nuly. Podle Apple Swift Documentation, 2026 je ARC vestavěno do překladače a pracuje ve fázi překladu, vkládající volání retain/release na správná místa. Na rozdíl od Garbage Collection ARC nevyžaduje samostatné vlákno kolektoru a nevytváří pauzy během provádění aplikace.

Hlavní body

  • ARC — Automatic Reference Counting, překladačový systém správy paměti ve Swift a Objective-C
  • Princip fungování — každý objekt má počítadlo referencí (retain count), při vynulování je objekt okamžitě uvolněn
  • Kvalifikátory — strong, weak a unowned určují, jak reference ovlivňuje počítadlo a životní cyklus objektu
  • Odlišnost od GC — ARC pracuje deterministicky ve fázi překladu, bez Stop-The-World pauz a vlákna kolektoru na pozadí
  • Retain Cycle — hlavní problém ARC: pokud na sebe dva objekty odkazují přes strong, jejich počítadlo nikdy nedosáhne nuly

Co je ARC?

ARC (Automatic Reference Counting) — je mechanismus správy paměti na úrovni překladače, představený společností Apple v Xcode 4.2 (2011) pro Objective-C a zděděný Swiftem. Na rozdíl od ruční správy paměti (Manual Retain-Release, MRR) ARC zcela automatizuje volání retain, release a autorelease, vkládá je ve fázi překladu bez účasti vývojáře.

ARC není garbage collector. Je to statická analýza s dynamickým vkládáním kódu: překladač analyzuje životnost objektů a umísťuje retain/release v bodech, kde jsou objekty vytvářeny, kopírovány nebo opouštějí rozsah platnosti. Výsledek — deterministické uvolňování paměti: objekt je smazán přesně v okamžiku, kdy na něj již neodkazuje žádná reference, bez zpoždění a pauz.

Podle WWDC 2011 Session 323 snížil přechod z MRR na ARC počet crash-bugů souvisejících s pamětí o 70 % v aplikacích Apple. Vývojáři přestali ručně vyvažovat retain/release, což eliminovalo celou třídu úniků a double-free chyb.

Jak funguje Automatic Reference Counting

Každý objekt v paměti má počítadlo referencí (retain count). Při vytvoření objektu je počítadlo nastaveno na 1. Když nová strong-reference ukazuje na objekt — počítadlo se zvyšuje (retain). Když strong-reference zmizí — počítadlo se snižuje (release). Při dosažení nuly je objekt okamžitě dealokován.

Swift překladač nevkládá retain/release při každém přiřazení — používá statickou analýzu pro optimalizaci. Například, pokud je objekt zaručeně nepoužit po přenosu, může překladač přeskočit zbytečný release/retain. Tato optimalizace se nazývá ARC Optimisation.

swift
class Person {
    let name: String
    init(name: String) {
        self.name = name
        print("\(name) inicializován (retain count: 1)")
    }
    deinit {
        print("\(name) dealokován")
    }
}

func testARC() {
    let p = Person(name: "Alice")  // retain count = 1
    let q = p                      // retain count = 2
    // q opouští rozsah
    // retain count = 1
    // p opouští rozsah
    // retain count = 0 → deinit
}

V tomto příkladu je vidět, jak ARC spravuje počítadlo: při přiřazení q = p se počítadlo zvyšuje, při opuštění rozsahu q — snižuje. Když poslední strong-reference zmizí, deinicializátor je okamžitě volán. Žádný garbage collector nečeká — paměť je uvolněna okamžitě.

ARC vs Garbage Collection: klíčové rozdíly

ARC a Garbage Collection řeší stejný úkol — automatickou správu paměti — ale zásadně odlišnými přístupy. Volba mezi nimi určuje architekturu jazyka: Swift (ARC) vs Java/Go (GC). Podíváme se na hlavní rozdíly.

CharakteristikaARC (Swift/ObjC)GC (Java/Go)
Okamžik uvolněníDeterministický: ihned při vynulování počítadlaNedeterministický: při následném sběru
Pauzy prováděníŽádné (vložení retain/release ve fázi překladu)Existují pauzy Stop-The-World (2–200 ms)
RežieZvyšování/snižování počítadla při každé referenciPrůchod grafem objektů, značení, uvolňování
ProblémyRetain Cycle (ruční řešení)Fragmentace haldy, úniky u zapomenutých referencí
Další vláknoNení vyžadovánoVyžaduje vlákno garbage collectoru

Klíčový kompromis: ARC poskytuje předvídatelnou životnost objektů a nulové pauzy, ale vyžaduje od vývojáře pochopení retain cycle a správnou volbu weak/unowned. GC od těchto starostí osvobozuje, ale za cenu nedeterministických pauz a dalšího vlákna.

Strong, Weak a Unowned: kvalifikátory referencí v ARC

ARC definuje tři typy kvalifikátorů referencí, z nichž každý ovlivňuje počítadlo a životní cyklus objektu jinak. Správná volba kvalifikátoru je základem bezpečné práce s pamětí ve Swift.

Strong

Strong — výchozí kvalifikátor. Každá strong-reference zvyšuje retain count objektu o 1. Dokud existuje alespoň jedna strong-reference, objekt žije. Všechny vlastnosti tříd a lokální proměnné ve Swift jsou ve výchozím nastavení strong. Strong-reference vytvářejí vztah vlastnictví: objekt A vlastní objekt B.

Weak

Weak — reference, která nezvyšuje retain count. Objekt může být dealokován, i když na něj weak-reference ukazuje. Po dealokaci je weak-reference automaticky nastavena na nil. Weak-reference jsou vždy deklarovány jako var s volitelným typem (?). Používají se k přerušení retain cycle, zejména v patternu delegate.

Unowned

Unowned — nevlastnící reference, která stejně jako weak nezvyšuje retain count. Nicméně unowned-reference nen\u00edstavena na nil po dealokaci — přístup k uvolněnému objektu způsobí crash. Unowned se používá, když je zaručeno, že objekt žije alespoň tak dlouho jako odkazující objekt. Typický scénář — uzávěry (closures) a vztahy rodič-dítě se zaručenou životností.

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

class CreditCard {
    let number: String
    unowned let customer: Customer   // unowned — nevlastní
    init(number: String, customer: Customer) {
        self.number = number
        self.customer = customer
    }
    deinit { print("Karta \(number) dealokována") }
}

var customer: Customer? = Customer(name: "Bob")
customer?.card = CreditCard(number: "1234", customer: customer!)
customer = nil
// Customer a CreditCard oba uvolněni — žádný retain cycle

Zde CreditCard používá unowned-reference na Customer. Customer vlastní kartu (strong) a karta nevlastní zákazníka (unowned). Když se Customer stane nil, oba objekty jsou uvolněny — retain cycle nevzniká. Pokud by card.customer bylo strong, cyklus by blokoval uvolnění.

Typické problémy ARC a jejich řešení

Navzdory automatizaci není ARC všelékem. Vývojáři se setkávají s několika typickými problémy, které vyžadují pochopení vnitřního mechanismu správy paměti.

Retain Cycle v uzávěrách

Uzávěry (closures) ve Swift zachycují vnější proměnné prostřednictvím strong-reference. Pokud je uzávěra přiřazena vlastnosti třídy a zachycuje self — vzniká retain cycle: třída drží uzávěru, uzávěra drží self. Řešení — capture list s weak nebo 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] vytváří weak-referenci na self uvnitř uzávěry. To přeruší potenciální retain cycle. Guard let self zaručuje, že objekt je živý před provedením kódu. weak self — standardní praxe pro asynchronní uzávěry ve Swift.

Výkon retain/release

Ačkoliv jsou retain/release lehké operace, časté zvyšování/snižování počítadla v horkých smyčkách vytváří režii. Ve Swift 5.9+ používá překladač optimalizaci, při které jsou zbytečné retain/release odstraněny, pokud analyzátor prokáže bezpečnost. Nicméně v Objective-C mohou být retain/release stále úzkým místem ve vysoce zatížených scénářích s miliony volání za sekundu.

Autorelease Pool

Autorelease Pool — mechanismus odloženého release, používaný v Objective-C a některých scénářích Swift. Objekty jsou umístěny do poolu a obdrží release při drain poolu. Ve smyčkách s velkým počtem dočasných objektů (např. parsování JSON) sníží vytvoření vlastního autoreleasepoolu špičkovou spotřebu operační paměti.

Často kladené otázky

Čím se ARC liší od ruční správy paměti (MRR)?

Při ruční správě (MRR) vývojář explicitně volal retain, release a autorelease. ARC vkládá tato volání automaticky ve fázi překladu, čímž eliminuje riziko double-free, úniky kvůli zapomenutému release a chyby vyvážení retain/release.

Může ARC pracovat s kódem C/C++?

ARC spravuje pouze objekty Objective-C a třídy Swift. Pro struktury a ukazatele C/C++ se ARC nepoužívá — tyto objekty jsou spravovány ručně nebo pomocí chytrých ukazatelů C++ (shared_ptr, unique_ptr). Objekty Core Foundation (CFString, CGColor) také nespadají pod ARC.

Kdy použít weak a kdy unowned?

weak — když může být objekt dealokován dříve než odkazující objekt (delegáty, asynchronní uzávěry). unowned — když je zaručeno, že objekt žije alespoň tak dlouho jako odkazující objekt (rodič-dítě, kde dítě nemůže existovat bez rodiče). Pokud si nejste jisti — zvolte weak.

Co jsou existenční typy a jak ovlivňují ARC?

Existenční typy (protocol as type) ve Swift zabalí hodnotu do speciálního kontejneru (existential container). To zvyšuje počet retain/release na hranicích protokolů. Ve Swift 5.7+ snižují opaque result types a some parametry režii odstraněním kontejneru.

Jak zkontrolovat retain count ve Swift?

Neexistuje přímé API pro čtení retain count ve Swift — je to považováno za detail implementace. Pro diagnostiku použijte Instruments (Allocations, Leaks) nebo Memory Debugger v Xcode. Tyto nástroje ukazují počet živých instancí třídy a řetězce držení.

Shrnutí

  • ARC — překladačový systém správy paměti pro Swift a Objective-C fungující na základě počítání referencí
  • Princip — každý objekt má retain count; při dosažení nuly je objekt okamžitě a deterministicky uvolněn
  • Odlišnost od GC — ARC pracuje bez vlákna na pozadí a Stop-The-World pauz, ale vyžaduje kontrolu retain cycle
  • Strong — zvyšuje počítadlo; weak a unowned — nezvyšují, ale unowned se při dealokaci nevynuluje
  • Uzávěry — hlavní příčina retain cycle ve Swift; capture list [weak self] — standardní řešení
  • Autorelease Pool — mechanismus odloženého uvolnění pro dočasné objekty ve smyčkách a vlastních scénářích
  • Diagnostika — Xcode Memory Debugger, Instruments a LeakCanary (přes ObjC bridge) pro hledání problémů

Vyvineme mobilní aplikaci na klíč

IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.

Prodiskutovat projekt

Přečtěte si také