Unowned Reference (referencia no poseída) es una referencia no propietaria en Swift que no incrementa el retain count del objeto y, a diferencia de weak, no se establece en nil después de que el objeto es liberado. Según Apple Swift Language Guide, 2026, unowned se usa cuando se garantiza que el objeto vive al menos tanto como el objeto que lo referencia. A diferencia de Weak Reference, unowned no requiere unwrap — es un tipo no opcional, lo que hace el código más limpio pero pone la responsabilidad en el desarrollador de garantizar el tiempo de vida.
Puntos Clave
Unowned Reference es una referencia no propietaria a un objeto en ARC que no incrementa su retain count. A diferencia de weak, una referencia unowned no se anula después de la desasignación del objeto: continúa apuntando a memoria que ya ha sido liberada. Acceder a tal referencia causa un crash en tiempo de ejecución con EXC_BAD_ACCESS.
El término “no poseída” refleja la semántica: el objeto existe, pero nadie es responsable de su tiempo de vida. El desarrollador declara explícitamente: “garantizo que este objeto estará vivo mientras yo lo referencie.” El compilador no verifica esta garantía — es un contrato a nivel del desarrollador.
Según Swift.org Documentation, 2026, las referencias unowned son preferibles a weak en escenarios con tiempo de vida garantizado porque: no requieren un tipo opcional (código más limpio), no requieren unwrap (menos force-unwrap o guard let), y no tienen sobrecarga de mantenimiento de una tabla weak de anulación. Sin embargo, cualquier incumplimiento del contrato resulta en un crash.
En Swift, las referencias unowned se declaran con la palabra clave unowned antes de let o var. A diferencia de weak, unowned puede ser tanto let como var, y no requiere un tipo opcional. Esta propiedad hace que unowned sea conveniente para referencias que no pueden ser nil por lógica de dominio.
class Country {
let name: String
var capital: City! // se establecerá después de la inicialización
init(name: String) { self.name = name }
}
class City {
let name: String
unowned let country: Country // ✅ unowned let — garantía de vida
init(name: String, country: Country) {
self.name = name
self.country = country
}
}
// Uso
let france = Country(name: "France")
let paris = City(name: "Paris", country: france)
france.capital = paris
// ✅ Country → City (strong), City → Country (unowned) — sin retain cycle
En este ejemplo, City unowned let country — una ciudad no puede existir sin un país. Si el país desaparece, la ciudad (y la referencia) pierden su significado. Semánticamente, este es un caso ideal para unowned: la garantía de tiempo de vida existe, no se necesita opcional, no se produce un retain cycle.
unowned var está permitido pero es menos común. Se usa cuando la referencia puede ser reemplazada (por ejemplo, reasignar un hijo a un padre diferente). Al reasignar, la desasignación del objeto antiguo es responsabilidad del propietario externo.
En Swift 5.0+, se introdujo soporte para unowned opcional (unowned let x: Type?). Esto es un compromiso: unowned garantiza que si la referencia no es nil, el objeto está vivo. El comportamiento al ser desasignado es un crash, igual que con unowned regular.
La elección entre unowned y weak es una de las decisiones frecuentes al diseñar arquitectura Swift. Examinemos los criterios y recomendaciones para cada caso.
| Criterio | Weak | Unowned |
|---|---|---|
| Opcional | Sí (Type?) | No (Type) |
| Anulación al desasignar | Auto a nil | No (riesgo de puntero colgante) |
| Tipo (let/var) | Solo var | let o var |
| Rendimiento | Sobrecarga de tabla weak | Mínimo (puntero simple) |
| Seguridad | Seguro (nil verificado) | Riesgo de EXC_BAD_ACCESS |
| Garantía de tiempo de vida | No requerida | Se requiere garantía explícita |
Use weak si hay la más mínima duda sobre el tiempo de vida del objeto. Weak es seguro, claro y no requiere prueba. Use unowned solo cuando pueda descartar todos los escenarios en los que el objeto podría ser desasignado antes. Casos típicos: un hijo que no existe sin un padre; un closure que se ejecuta sincrónicamente; acceso a un objeto dentro de su inicializador.
Según Airbnb Swift Style Guide, 2025, en bases de código grandes se recomienda usar weak por defecto y unowned solo con un comentario explícito que explique la garantía de tiempo de vida. Esto reduce el riesgo de crashes no obvios durante la refactorización.
Los closures son el segundo caso de uso más frecuente para unowned después de las relaciones padre-hijo. La lista de captura [unowned self] se usa cuando se garantiza que self sobrevive al closure. Examinemos escenarios correctos e incorrectos.
Closures sincrónicos — sorted, filter, map. Se ejecutan inmediatamente en el hilo actual, self está definitivamente vivo. Una lista de captura con unowned es aceptable aquí y da un código más limpio.
class DataProcessor {
var items: [Int] = [3, 1, 4, 1, 5]
func processSorted() {
// ✅ unowned self — sorted se ejecuta sincrónicamente, self está garantizadamente 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 }
}
Closures asincrónicos — con retrasos, solicitudes de red, animaciones. Self puede ser desasignado entre la programación del closure y su ejecución. Aquí unowned self lleva a un crash. Use [weak self].
class NetworkLoader {
func loadData() {
// ❌ PELIGROSO: unowned self en closure asíncrono
URLSession.shared.dataTask(with: url) { [unowned self] data, _, _ in
self.handleResponse(data) // CRASH si self es liberado
}.resume()
}
func handleResponse(_ data: Data?) { }
// ✅ CORRECTO: weak self + guard
func loadDataSafe() {
URLSession.shared.dataTask(with: url) { [weak self] data, _, _ in
guard let self else { return }
self.handleResponse(data)
}.resume()
}
}
Recuerde la regla: unowned self — solo para closures sincrónicos que se ejecutan inmediatamente. Para closures asincrónicos, siempre use weak self + guard let. Excepción: si mantiene explícitamente una referencia al objeto hasta que el closure se complete (por ejemplo, manteniendo una referencia fuerte en otra variable).
Unowned es una herramienta poderosa pero peligrosa. Examinemos escenarios del mundo real donde unowned puede llevar a crashes y métodos para minimizar el riesgo.
El principal riesgo de unowned es un cambio en la lógica de negocio que invalide la garantía de tiempo de vida. Un desarrollador refactoriza el código: cambia la propiedad, introduce desasignación diferida, añade almacenamiento en caché — y la referencia unowned se convierte en una bomba de tiempo. El compilador no advertirá — solo un crash en el dispositivo del usuario.
Recomendación: use unowned solo cuando la garantía de tiempo de vida sea obvia y esté documentada. Añada un comentario a cada unowned: por qué esta referencia es segura y bajo qué condiciones podría violarse.
UIKit es un área de alto riesgo para unowned. Un ViewController puede ser desasignado en cualquier momento durante la navegación (pop, dismiss), descarga de memoria o cambios de orientación. Si pasa un ViewController a un closure con unowned self, self puede ser nil al regresar del fondo o al completar una animación.
Para reducir el riesgo al usar unowned, siga estas reglas:
// Ejemplo: referencia unowned documentada con justificación explícita
class InvoiceLineItem {
let productName: String
let price: Decimal
// unowned Invoice — InvoiceLineItem no puede existir sin Invoice.
// Invoice crea Item y lo elimina cuando se borra.
// Garantía: Invoice vive al menos tanto como Item.
unowned let invoice: Invoice
init(productName: String, price: Decimal, invoice: Invoice) {
self.productName = productName
self.price = price
self.invoice = invoice
}
}
// Esta es una garantía fuerte: Invoice elimina todos los Items en deinit.
// violar la garantía = un bug en la lógica de negocio que necesita ser corregido.
Documentar garantías es un estándar profesional. En proyectos grandes (Airbnb, Uber), la revisión de código requiere justificación para cada unowned. Si la garantía no es obvia, use weak. Un comentario en unowned ayuda a los desarrolladores futuros a entender por qué no se usó weak aquí y qué condiciones podrían romper la garantía.
Preguntas Frecuentes
Crash en tiempo de ejecución con EXC_BAD_ACCESS. Swift no verifica la validez de una referencia unowned al acceder — es simplemente un puntero “crudo”. Si el objeto es liberado, la memoria se sobrescribe y acceder a ella termina de forma fatal. Esta es una excepción no capturable (no es try-catch).
Sí, si el protocolo hereda de AnyObject. Unowned funciona con todos los tipos de referencia: clases, protocolos AnyObject, objetos Objective-C. Los tipos de valor (struct, enum) no soportan unowned porque no participan en ARC.
Cuando la garantía de tiempo de vida es absoluta y obvia — unowned es más seguro desde una perspectiva de diseño: no requiere unwrap, no puede ser nil y no enmascara errores. Si un objeto no puede existir sin un padre, unowned lo convierte en un contrato explícito, mientras que weak difumina la garantía.
Sí: unowned es más rápido porque no requiere acceso a la tabla weak en tiempo de ejecución para la anulación. En la mayoría de las aplicaciones la diferencia es imperceptible, pero en escenarios de alta carga con millones de accesos, unowned puede ser 10–20% más rápido en lecturas.
La refactorización es el principal peligro para unowned. Cambiar el tiempo de vida del objeto (caché, operaciones asíncronas, reutilización) puede romper la garantía. El compilador no advertirá. Solución: migre a weak al cambiar la arquitectura o añada un comentario de advertencia.
Resumen
unowned let o unowned var; puede ser no opcional y opcional (Swift 5.0+)Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también