Swift es un lenguaje de programación muy famoso por hacer que la gestión de la memoria “simplemente funcione”. Esto es gracias a su sistema de Automatic Reference Counting o ARC. No obstante, no todo es automático, ya que cuando se trata de manejar ciclos de referencias fuertes, debemos tener en cuenta conceptos como el de unowned references en Swift. Si, como desarrollador, no sabes qué son, no te preocupes, en este artículo te explicamos todo al respecto.
¿Qué son las unowned references en Swift?
En Swift, las referencias a instancias de clases son fuertes por defecto. Esto quiere decir que cada referencia incrementa el conteo de referencias de la instancia y así evita que sea liberada por ARC. Empero, hay casos en donde estas referencias fuertes pueden causar ciclos de referencias que ARC no puede resolver por sí solo.
Aquí es donde entran las unowned references o referencias sin propietario. Estas referencias no retienen a la instancia de clase que apuntan y no incrementan el conteo de referencias del objeto. A diferencia de las referencias débiles o weak references, las unowned references en Swift son no opcionales. Esto indica que asumen que siempre apuntarán a una instancia válida durante su ciclo de vida.
Algunas de las características que conservan las unowned references en Swift son:
- No afectan el conteo de referencias: Al no ser una referencia fuerte, no aumentan ni disminuyen el número de referencias de un objeto.
- No son opcionales: Esto implica que no pueden contener
nil
. Si intentas acceder a una referencia no válida, tu aplicación podría fallar. - Evitan ciclos de referencias fuertes: Son útiles cuando dos instancias de clases necesitan apuntarse mutuamente, pero una de ellas debe garantizar que no se mantendrá una referencia fuerte.
Para entenderlas mejor, veamos un ejemplo:
class Customer {
let name: String
var card: CreditCard?
init(name: String) {
self.name = name
}
deinit {
print("\(name) ha sido liberado de memoria")
}
}
class CreditCard {
let number: UInt64
unowned let customer: Customer
init(number: UInt64, customer: Customer) {
self.number = number
self.customer = customer
}
deinit {
print("Tarjeta #\(number) ha sido liberada de memoria")
}
}
var john: Customer? = Customer(name: "John")
john?.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
john = nil
// Salida:
// John ha sido liberado de memoria
// Tarjeta #1234567890123456 ha sido liberada de memoria
En este ejemplo, la clase Customer tiene una referencia fuerte a CreditCard, mientras que la tarjeta mantiene una referencia no propietaria (unowned) hacia el cliente. Cuando liberamos al cliente asignando nil (ausencia de un valor), tanto el cliente como la tarjeta son de-inicializados correctamente, evitando un ciclo de referencias.
¿Cómo funcionan las unowned references en Swift dentro del ARC?
Swift utiliza ARC para gestionar de forma automática la memoria asignada a instancias de clases. Cada vez que creas una instancia, ARC asigna memoria y aumenta el conteo de referencias cada vez que alguien hace referencia al objeto.
Cuando el conteo llega a cero, la memoria de la instancia es liberada. No obstante, si dos instancias mantienen referencias fuertes mutuas (un ciclo), el conteo nunca llegará a cero. Aquí es donde las unowned references en Swift cobran valor.
Aunque ambas referencias, tanto las weak como las unowned, evitan ciclos, su implementación y uso tienen diferencias que vale la pena mencionar:
Característica | Weak | Unowned |
---|---|---|
Es opcional | Sí (var tenant: Person?) | No (unowned let customer: Customer) |
Puede ser nil automáticamente | Sí | No |
Requiere cuidado del desarrollador | Menos | Más |
Uso típico | Cuando la referencia puede ser nil en algún momento | Cuando la referencia nunca será nil |
¿Cuándo utilizar unowned references en Swift?
🔴 ¿Quieres entrar de lleno al Desarrollo Mobile? 🔴
Descubre el Desarrollo de Apps Móviles Full Stack Bootcamp de KeepCoding. La formación más completa del mercado y con empleabilidad garantizada
👉 Prueba gratis el Bootcamp en Desarrollo de Apps Móviles por una semanaDebes utilizar unowned references cuando sabes con certeza que la instancia referenciada siempre existirá mientras exista la referencia. Algunos de estos escenarios incluyen:
- Relaciones de igual a igual: Por ejemplo, un cliente y su tarjeta de crédito. La tarjeta depende de la existencia del cliente.
- Evitar ciclos en modelos de datos: En estructuras como departamentos y cursos dentro de una universidad, donde cada curso pertenece a un departamento y puede apuntar al siguiente curso.
Ejemplifiquemos:
class Department {
var name: String
var courses: [Course]
init(name: String) {
self.name = name
self.courses = []
}
}
class Course {
let name: String
unowned let department: Department
unowned var nextCourse: Course?
init(name: String, department: Department) {
self.name = name
self.department = department
}
}
let department = Department(name: "Ciencias de la Computación")
let intro = Course(name: "Programación 101", department: department)
let advanced = Course(name: "Estructuras de Datos", department: department)
intro.nextCourse = advanced
department.courses.append(contentsOf: [intro, advanced])
En este ejemplo las relaciones entre cursos y departamentos se gestionan sin ciclos de referencias gracias a las unowned references.
Debes tener cuidado con…
Aunque son un gran elemento de desarrollo, las unowned references en Swift requieren atención:
- Si intentas acceder a una instancia ya liberada, obtendrás un error en tiempo de ejecución.
- No las uses si la referencia puede ser nil. En esos casos, las referencias weak son una mejor opción.
En este artículo has podido conocer todo lo relacionado con las referencias sin propietario o unowned references en Swift, así como en qué consisten sus principales características. No dudes en continuar con tu formación y, para lograr convertirte en un verdadero experto, apúntate en nuestro Desarrollo de Apps Móviles Full Stack Bootcamp. Aquí recibirás una formación íntegra y de calidad que te permitirá destacar frente a tus competidores y adentrarte en el mercado laboral como profesional del desarrollo mobile. ¡Atrévete a dar un paso más en tu aprendizaje y pide más información sobre este bootcamp!