Unowned Reference: ce este, sintaxa și aplicarea în aplicațiile mobile

Autor: IT Sectr Publicat: 2026-03-30 Timp de citire: 9 min

Unowned Reference (referință fără proprietar) — este o referință care nu deține în Swift, care nu mărește retain count al obiectului și, spre deosebire de weak, nu se setează la nil după eliberarea acestuia. Conform Apple Swift Language Guide, 2026, unowned se aplică atunci când este garantat că obiectul trăiește cel puțin cât obiectul care se referă la el. Spre deosebire de Weak Reference, unowned nu necesită unwrap — este un tip non-optional, ceea ce face codul mai curat, dar pune responsabilitatea garanției duratei de viață asupra dezvoltatorului.

Puncte principale

  • Unowned Reference — referință care nu deține fără zeroing automat; non-optional, nu mărește retain count
  • Garanție — se aplică atunci când obiectul garantat nu poate fi eliberat înaintea obiectului care se referă la el
  • Diferența de weak — unowned nu este zeroizat la nil (risc de crash), weak este zeroizat (sigur)
  • Scenarii — parent-child cu garanție de viață, closure cu unowned self, singletonuri și Service Locator
  • Risc — accesarea unui obiect unowned eliberat cauzează runtime crash (EXC_BAD_ACCESS)

Ce este Unowned Reference?

Unowned Reference — este o referință care nu deține către un obiect în ARC, care nu mărește retain count-ul acestuia. Spre deosebire de weak, unowned nu este zeroizată după deallocarea obiectului: continuă să indice spre zona de memorie care a fost deja eliberată. Accesarea unei astfel de referințe cauzează runtime crash cu EXC_BAD_ACCESS.

Termenul „fără proprietar“ reflectă semantica: obiectul există, dar nimeni nu răspunde pentru durata sa de viață. Dezvoltatorul declară explicit: „garantez că acest obiect va trăi cât timp mă refer la el“. Compilatorul nu verifică această garanție — este un contract la nivelul dezvoltatorului.

Conform Swift.org Documentation, 2026, referințele unowned sunt preferate față de weak în scenariile cu durata de viață garantată deoarece: nu necesită un tip opțional (cod mai curat), nu necesită unwrap (mai puțin force-unwrap sau guard let) și nu au overhead pentru întreținerea tabelei weak zeroing. Cu toate acestea, orice încălcare a contractului — crash.

Sintaxa unowned în Swift

În Swift, referințele unowned se declară cu cuvântul cheie unowned înainte de let sau var. Spre deosebire de weak, unowned poate fi atât let, cât și var și nu necesită un tip opțional. Această proprietate face unowned convenabil pentru referințele care nu pot fi nil conform logicii domeniului.

swift
class Country {
    let name: String
    var capital: City!           // va fi setat după inițializare
    init(name: String) { self.name = name }
}

class City {
    let name: String
    unowned let country: Country   // ✅ unowned let — garanție de viață

    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

// Utilizare
let france = Country(name: "France")
let paris = City(name: "Paris", country: france)
france.capital = paris
// ✅ Country → City (strong), City → Country (unowned) — fără retain cycle

În acest exemplu City unowned let country — orașul nu poate exista fără țară. Dacă țara dispare, orașul (și referința) își pierd sensul. Semantic, acesta este un caz ideal pentru unowned: garanția duratei de viață există, optional nu este necesar, retain cycle nu apare.

unowned var

unowned var este permis, dar apare mai rar. Se folosește când referința poate fi înlocuită (de exemplu, reatașarea unui copil la un alt părinte). La înlocuire, eliberarea obiectului vechi — responsabilitatea proprietarului extern.

Unowned Optional

În Swift 5.0+ a apărut suportul pentru unowned optional (unowned let x: Type?). Este un compromis: unowned garantează că dacă referința nu este nil, obiectul este viu. Comportamentul la eliberare — crash, ca și în cazul unowned obișnuit.

Unowned vs Weak: când să folosești ce

Alegerea între unowned și weak — una dintre deciziile frecvente la proiectarea arhitecturii Swift. Să examinăm criteriile și recomandările pentru fiecare caz.

CriteriuWeakUnowned
OptionalDa (Type?)Nu (Type)
Zeroing la deallocareAuto la nilNu (risc de pointer agățat)
Tip (let/var)Doar varlet sau var
PerformanțăCosturi pentru weak-tabelMinime (pointer simplu)
SiguranțăSigur (nil verificat)Risc EXC_BAD_ACCESS
Garanția duratei de viațăNu este necesarăNecesită garanție explicită

Regula practică

Folosește weak dacă există măcar cea mai mică îndoială cu privire la durata de viață a obiectului. Weak este sigur, de înțeles și nu necesită dovezi. Folosește unowned doar când ai exclus toate scenariile în care obiectul s-ar putea elibera mai devreme. Cazuri tipice: copil care nu există fără părinte; closure care se execută sincron; referirea la un obiect în cadrul inițializatorului său.

Conform Airbnb Swift Style Guide, 2025, în bazele de cod mari se recomandă utilizarea weak implicit și unowned — doar cu un comentariu explicit care explică garanția duratei de viață. Aceasta reduce riscul de crashuri neevidente la refactorizare.

Unowned self în closure

Closure-urile — al doilea scenariu ca frecvență de utilizare a unowned după relațiile parent-child. Capture list [unowned self] se aplică atunci când self garantează că trăiește mai mult decât closure-ul. Să examinăm scenariile corecte și incorecte.

Când unowned self este sigur

Closure-uri sincrone — sorted, filter, map. Se execută imediat în threadul curent, self este cu siguranță viu. Capture list cu unowned este acceptabil aici și oferă cod mai curat.

swift
class DataProcessor {
    var items: [Int] = [3, 1, 4, 1, 5]

    func processSorted() {
        // ✅ unowned self — sorted se execută sincron, self garantat viu
        let sorted = items.sorted { [unowned self] a, b in
            return self.customCompare(a, b)
        }
    }

    func customCompare(_ a: Int, _ b: Int) -> Bool { return a < b }
}

Când unowned self este periculos

Closure-uri asincrone — cu întârziere, cereri de rețea, animații. Self poate fi eliberat între plasarea closure-ului și executarea sa. Aici unowned self → crash. Folosește [weak self].

swift
class NetworkLoader {
    func loadData() {
        // ❌ PERICULOS: unowned self în closure asincron
        URLSession.shared.dataTask(with: url) { [unowned self] data, _, _ in
            self.handleResponse(data)  // CRASH dacă self este eliberat
        }.resume()
    }

    func handleResponse(_ data: Data?) { }

    // ✅ CORECT: weak self + guard
    func loadDataSafe() {
        URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
            guard let self else { return }
            self.handleResponse(data)
        }.resume()
    }
}

Țe minte regula: unowned self — doar pentru closure-uri sincrone care se execută imediat. Pentru asincrone — întotdeauna weak self + guard let. Excepție: dacă păstrezi explicit o referință la obiect până la terminarea closure-ului (de exemplu, prin păstrarea unui capture puternic într-o altă variabilă).

Riscuri unowned și cum să le eviți

Unowned — un instrument puternic, dar periculos. Să examinăm scenariile reale în care unowned poate duce la crash și metodele de minimizare a riscului.

Refactorizarea și schimbarea garanțiilor

Riscul principal al unowned — modificarea logicii de business prin care garanția duratei de viață încetează să fie respectată. Dezvoltatorul refactorizează codul: schimbă proprietatea, introduce eliberarea întârziată, adaugă cache — și referința unowned se transformă într-o bombă cu ceas. Compilatorul nu va avertiza — doar crash pe dispozitivul utilizatorului.

Recomandare: folosește unowned doar când garanția duratei de viață este evidentă și documentată. Adaugă un comentariu la fiecare unowned: de ce această referință este sigură și în ce condiții poate fi încălcată.

Unowned în ierarhiile UIKit

UIKit — zonă de risc ridicat pentru unowned. ViewController poate fi eliberat în orice moment la navigare (pop, dismiss), descărcare din memorie, schimbare de orientare. Dacă transmiți ViewController-ul într-un closure cu unowned self — la revenirea din fundal sau la terminarea animației self poate fi nil.

Cele mai bune practici

Pentru a reduce riscul la utilizarea unowned, urmează aceste reguli:

  • Preferă weak implicit — weak este sigur, unowned este o optimizare, nu un standard
  • Documentează garanțiile — pentru fiecare unowned scrie un comentariu cu justificare
  • Evită unowned în ViewController — ciclul de viață UIKit este imprevizibil pentru garanțiile unowned
  • Folosește unowned doar pentru closure-uri sincrone — sorted, filter, map — candidați siguri
  • Verifică la code review — fiecare unowned necesită justificare de la autorul codului
  • Migrează la weak la cele mai mici îndoieli — pierderea în lizibilitate (un guard let) este mai mică decât un crash în producție
swift
// Exemplu: referință unowned documentată cu justificare explicită
class InvoiceLineItem {
    let productName: String
    let price: Decimal

    // unowned Invoice — InvoiceLineItem nu poate exista fără Invoice.
    // Invoice creează Item și îl șterge la ștergerea sa.
    // Garanție: Invoice trăiește cel puțin cât Item.
    unowned let invoice: Invoice

    init(productName: String, price: Decimal, invoice: Invoice) {
        self.productName = productName
        self.price = price
        self.invoice = invoice
    }
}

// Aceasta este o garanție puternică: Invoice șterge toate Item în deinit.
// încălcarea garanției = bug în logica de business care trebuie reparat.

Documentarea garanțiilor — standard profesional. În proiectele mari (Airbnb, Uber) code review necesită justificarea fiecărui unowned. Dacă garanția nu este evidentă — folosește weak. Comentariul la unowned ajută viitorii dezvoltatori să înțeleagă de ce aici nu este weak și ce condiții pot rupe garanția.

Întrebări frecvente

Ce se întâmplă la accesarea unei referințe unowned după eliberarea obiectului?

Runtime crash cu EXC_BAD_ACCESS. Swift nu verifică validitatea referinței unowned la acces — este doar un pointer „brut“. Dacă obiectul a fost eliberat, memoria este suprascrisă, iar accesarea ei se termină cu avarie. Aceasta este o excepție neacoperită (nu try-catch).

Se poate folosi unowned cu protocoale?

Da, dacă protocolul moștenește din AnyObject. Unowned funcționează cu toate tipurile de referință: clase, protocoale AnyObject, obiecte Objective-C. Tipurile de valoare (struct, enum) nu suportă unowned deoarece nu participă la ARC.

Când este unowned mai sigur decât weak?

Când garanția duratei de viață este absolută și evidentă — unowned este mai sigur din punct de vedere al designului: nu necesită unwrap, nu poate fi nil, nu maschează erorile. Dacă obiectul nu poate exista fără părinte, unowned face acest lucru un contract explicit, iar weak estompează garanția.

Există diferență de performanță între unowned și weak?

Da: unowned este mai rapid, deoarece nu necesită acces la tabela weak runtime pentru zeroing. În majoritatea aplicațiilor diferența este insesizabilă, dar în scenariile cu încărcare ridicată cu milioane de accesări, unowned poate fi cu 10–20% mai rapid la citire.

Cum afectează refactorizarea garanțiile unowned?

Refactorizarea — principalul pericol pentru unowned. Modificarea duratei de viață a obiectului (cache, operații asincrone, reutilizare) poate încălca garanția. Compilatorul nu va avertiza. Soluția: migrează la weak la schimbarea arhitecturii sau adaugă un comentariu de avertizare.

Rezumat

  • Unowned Reference — referință care nu deține fără zeroing; non-optional, nu mărește retain count
  • Garanție — necesită dovadă explicită că obiectul trăiește cel puțin cât codul care se referă la el
  • Sintaxăunowned let sau unowned var; poate fi non-optional și optional (Swift 5.0+)
  • Unowned vs Weak — unowned este mai rapid și mai curat, dar weak este mai sigur; weak — alegerea implicită
  • Closure-uri — unowned self doar pentru closure-uri sincrone; asincrone necesită [weak self]
  • Documentare — fiecare unowned ar trebui să aibă un comentariu cu justificarea garanției
  • Recomandare — la îndoială alege weak; unowned — pentru contracte explicite și documentate

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și