Unowned Reference (riferimento non posseduto) è un riferimento non proprietario in Swift che non aumenta il retain count dell'oggetto e, a differenza di weak, non viene impostato a nil dopo la liberazione dell'oggetto. Secondo Apple Swift Language Guide, 2026, unowned viene utilizzato quando è garantito che l'oggetto viva almeno quanto l'oggetto che lo riferisce. A differenza di Weak Reference, unowned non richiede unwrap — è un tipo non opzionale, che rende il codice più pulito ma pone la responsabilità della garanzia del ciclo di vita sullo sviluppatore.
Punti Chiave
Unowned Reference è un riferimento non proprietario a un oggetto in ARC che non aumenta il suo retain count. A differenza di weak, un riferimento unowned non viene azzerato dopo la deallocazione dell'oggetto: continua a puntare a memoria già liberata. Accedere a tale riferimento causa un crash a runtime con EXC_BAD_ACCESS.
Il termine “non posseduto” riflette la semantica: l'oggetto esiste, ma nessuno è responsabile del suo ciclo di vita. Lo sviluppatore dichiara esplicitamente: “garantisco che questo oggetto sarà vivo finché lo riferisco.” Il compilatore non verifica questa garanzia — è un contratto a livello di sviluppatore.
Secondo Swift.org Documentation, 2026, i riferimenti unowned sono preferiti a weak negli scenari con ciclo di vita garantito perché: non richiedono un tipo opzionale (codice più pulito), non richiedono unwrap (meno force-unwrap o guard let), e non hanno overhead di manutenzione di una tabella weak di azzeramento. Tuttavia, qualsiasi violazione del contratto risulta in un crash.
In Swift, i riferimenti unowned sono dichiarati con la parola chiave unowned prima di let o var. A differenza di weak, unowned può essere sia let che var, e non richiede un tipo opzionale. Questa proprietà rende unowned conveniente per riferimenti che non possono essere nil per logica di dominio.
class Country {
let name: String
var capital: City! // verrà impostato dopo l'inizializzazione
init(name: String) { self.name = name }
}
class City {
let name: String
unowned let country: Country // ✅ unowned let — garanzia di vita
init(name: String, country: Country) {
self.name = name
self.country = country
}
}
// Utilizzo
let france = Country(name: "France")
let paris = City(name: "Paris", country: france)
france.capital = paris
// ✅ Country → City (strong), City → Country (unowned) — nessun retain cycle
In questo esempio, City unowned let country — una città non può esistere senza un paese. Se il paese scompare, la città (e il riferimento) perdono il loro significato. Semanticamente, questo è un caso ideale per unowned: la garanzia del ciclo di vita esiste, l'opzionale non è necessario, il retain cycle non si verifica.
unowned var è permesso ma meno comune. Viene utilizzato quando il riferimento può essere sostituito (ad esempio, riassegnare un figlio a un genitore diverso). Al momento della riassegnazione, la deallocazione dell'oggetto vecchio è responsabilità del proprietario esterno.
In Swift 5.0+, è stato introdotto il supporto per unowned opzionale (unowned let x: Type?). Questo è un compromesso: unowned garantisce che se il riferimento non è nil, l'oggetto è vivo. Il comportamento alla deallocazione è un crash, come con unowned normale.
La scelta tra unowned e weak è una delle decisioni frequenti quando si progetta l'architettura Swift. Esaminiamo i criteri e le raccomandazioni per ogni caso.
| Criterio | Weak | Unowned |
|---|---|---|
| Opzionale | Sì (Type?) | No (Type) |
| Azzeramento alla deallocazione | Auto a nil | No (rischio di puntatore pendente) |
| Tipo (let/var) | Solo var | let o var |
| Prestazioni | Overhead della tabella weak | Minimo (puntatore semplice) |
| Sicurezza | Sicuro (nil verificato) | Rischio di EXC_BAD_ACCESS |
| Garanzia del ciclo di vita | Non richiesta | Garanzia esplicita richiesta |
Usa weak se c'è anche il minimo dubbio sul ciclo di vita dell'oggetto. Weak è sicuro, chiaro e non richiede prove. Usa unowned solo quando puoi escludere tutti gli scenari in cui l'oggetto potrebbe essere deallocato prima. Casi tipici: un figlio che non esiste senza un genitore; una closure che si esegue in modo sincrono; accesso a un oggetto all'interno del suo inizializzatore.
Secondo Airbnb Swift Style Guide, 2025, in grandi basi di codice si consiglia di usare weak per impostazione predefinita e unowned solo con un commento esplicito che spieghi la garanzia del ciclo di vita. Ciò riduce il rischio di crash non ovvi durante il refactoring.
Le closure sono il secondo caso d'uso più frequente per unowned dopo le relazioni genitore-figlio. La lista di cattura [unowned self] viene utilizzata quando è garantito che self sopravviva alla closure. Esaminiamo scenari corretti e errati.
Closure sincrone — sorted, filter, map. Vengono eseguite immediatamente nel thread corrente, self è sicuramente vivo. Una lista di cattura con unowned è accettabile qui e produce codice più pulito.
class DataProcessor {
var items: [Int] = [3, 1, 4, 1, 5]
func processSorted() {
// ✅ unowned self — sorted viene eseguito in modo sincrono, self è garantitamente vivo
let sorted = items.sorted { [unowned self] a, b in
return self.customCompare(a, b)
}
}
func customCompare(_ a: Int, _ b: Int) -> Bool { return a < b }
}
Closure asincrone — con ritardi, richieste di rete, animazioni. Self può essere deallocato tra la pianificazione della closure e la sua esecuzione. Qui unowned self porta a un crash. Usa [weak self].
class NetworkLoader {
func loadData() {
// ❌ PERICOLOSO: unowned self in closure asincrona
URLSession.shared.dataTask(with: url) { [unowned self] data, _, _ in
self.handleResponse(data) // CRASH se self viene liberato
}.resume()
}
func handleResponse(_ data: Data?) { }
// ✅ CORRETTO: weak self + guard
func loadDataSafe() {
URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
guard let self else { return }
self.handleResponse(data)
}.resume()
}
}
Ricorda la regola: unowned self — solo per closure sincrone che vengono eseguite immediatamente. Per closure asincrone, usa sempre weak self + guard let. Eccezione: se mantieni esplicitamente un riferimento all'oggetto fino al completamento della closure (ad esempio, mantenendo un riferimento forte in un'altra variabile).
Unowned è uno strumento potente ma pericoloso. Esaminiamo scenari reali in cui unowned può portare a crash e metodi per minimizzare il rischio.
Il rischio principale di unowned è un cambiamento nella logica di business che invalida la garanzia del ciclo di vita. Uno sviluppatore rifattorizza il codice: cambia la proprietà, introduce deallocazione differita, aggiunge caching — e il riferimento unowned diventa una bomba a orologeria. Il compilatore non avviserà — solo un crash sul dispositivo dell'utente.
Raccomandazione: usa unowned solo quando la garanzia del ciclo di vita è ovvia e documentata. Aggiungi un commento a ogni unowned: perché questo riferimento è sicuro e in quali condizioni potrebbe essere violato.
UIKit è un'area ad alto rischio per unowned. Un ViewController può essere deallocato in qualsiasi momento durante la navigazione (pop, dismiss), scaricamento della memoria o cambi di orientamento. Se passi un ViewController a una closure con unowned self, self potrebbe essere nil al ritorno dallo sfondo o al completamento di un'animazione.
Per ridurre il rischio quando usi unowned, segui queste regole:
// Esempio: riferimento unowned documentato con giustificazione esplicita
class InvoiceLineItem {
let productName: String
let price: Decimal
// unowned Invoice — InvoiceLineItem non può esistere senza Invoice.
// Invoice crea Item e lo rimuove quando viene eliminato.
// Garanzia: Invoice vive almeno quanto Item.
unowned let invoice: Invoice
init(productName: String, price: Decimal, invoice: Invoice) {
self.productName = productName
self.price = price
self.invoice = invoice
}
}
// Questa è una garanzia forte: Invoice rimuove tutti gli Item in deinit.
// violare la garanzia = un bug nella logica di business che deve essere corretto.
Documentare le garanzie è uno standard professionale. In grandi progetti (Airbnb, Uber), la revisione del codice richiede una giustificazione per ogni unowned. Se la garanzia non è ovvia, usa weak. Un commento su unowned aiuta gli sviluppatori futuri a capire perché weak non è stato usato qui e quali condizioni potrebbero rompere la garanzia.
Domande Frequenti
Crash a runtime con EXC_BAD_ACCESS. Swift non verifica la validità di un riferimento unowned all'accesso — è semplicemente un puntatore “grezzo”. Se l'oggetto viene liberato, la memoria viene sovrascritta e accedervi termina fatalmente. Questa è un'eccezione non catturabile (non try-catch).
Sì, se il protocollo eredita da AnyObject. Unowned funziona con tutti i tipi riferimento: classi, protocolli AnyObject, oggetti Objective-C. I tipi valore (struct, enum) non supportano unowned perché non partecipano ad ARC.
Quando la garanzia del ciclo di vita è assoluta e ovvia — unowned è più sicuro dal punto di vista del design: non richiede unwrap, non può essere nil e non maschera errori. Se un oggetto non può esistere senza un genitore, unowned lo rende un contratto esplicito, mentre weak offusca la garanzia.
Sì: unowned è più veloce perché non richiede accesso alla tabella weak a runtime per l'azzeramento. Nella maggior parte delle applicazioni la differenza è impercettibile, ma in scenari ad alto carico con milioni di accessi, unowned può essere 10–20% più veloce in lettura.
Il refactoring è il pericolo principale per unowned. Modificare il ciclo di vita dell'oggetto (caching, operazioni asincrone, riutilizzo) può rompere la garanzia. Il compilatore non avviserà. Soluzione: migra a weak quando cambi architettura o aggiungi un commento di avvertimento.
Riepilogo
unowned let o unowned var; può essere non opzionale e opzionale (Swift 5.0+)Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche