Sobes.tech
Middle

¿Qué tipos de enlaces existen en Swift?

sobes.tech AI

Respuesta de la IA

En Swift, existen tres tipos principales de referencias a instancias de clases:

  1. Referencia fuerte (Strong Reference):

    • Es el tipo de referencia por defecto.
    • La referencia fuerte incrementa el contador de referencias del objeto.
    • El objeto no será liberado de la memoria mientras exista al menos una referencia fuerte.
    • La causa principal de fugas de memoria en ciclos de referencias fuertes (strong reference cycles).
    class Person {
        let name: String
        init(name: String) { self.name = name }
        deinit { print("\(name) está siendo destruido") }
    }
    
    var reference1: Person? = Person(name: "John")
    // reference1 ahora es una referencia fuerte, el contador de referencias de Person aumenta
    
  2. Referencia débil (Weak Reference):

    • Se declara usando la palabra clave weak.
    • La referencia débil no incrementa el contador de referencias del objeto.
    • Se usa para prevenir ciclos de referencias fuertes (strong reference cycles).
    • Siempre es opcional (Optional), porque el objeto al que apunta la referencia débil puede ser destruido en cualquier momento. Cuando el objeto se destruye, la referencia débil automáticamente se vuelve nil.
    class Apartment {
        let unit: String
        weak var tenant: Person? // Referencia débil
        init(unit: String) { self.unit = unit }
        deinit { print("Apartamento \(unit) está siendo destruido") }
    }
    
    var john: Person? = Person(name: "John")
    var unit4A: Apartment? = Apartment(unit: "4A")
    
    john?.apartment = unit4A // Si Apartment tuviera una referencia fuerte a Person
    unit4A?.tenant = john   // Referencia débil
    
    // Después de eliminar las referencias fuertes, los objetos serán destruidos
    john = nil
    unit4A = nil
    // Salida: "John está siendo destruido", "Apartamento 4A está siendo destruido"
    // Si tenant fuera una referencia fuerte, ocurriría una fuga de memoria (ciclo fuerte)
    
  3. Referencia no poseída (Unowned Reference):

    • Se declara usando la palabra clave unowned.
    • Similar a la referencia débil, no incrementa el contador de referencias del objeto.
    • También se usa para prevenir ciclos de referencias fuertes.
    • A diferencia de weak, no es opcional (Optional) y supone que el objeto al que apunta existirá durante toda la "vida" de la referencia no poseída.
    • Si el objeto al que apunta la referencia unowned se destruye antes de que la referencia unowned sea inválida, ocurrirá un error en tiempo de ejecución (runtime error).
    • Es adecuada en situaciones donde un objeto siempre existe mientras otro objeto relacionado también exista (por ejemplo, "padre-hijo", donde el padre posee al hijo, pero el hijo no posee al padre de forma fuerte).
    class Customer {
        let name: String
        var card: CreditCard?
        init(name: String) { self.name = name }
        deinit { print("\(name) está siendo destruido") }
    }
    
    class CreditCard {
        let number: Int
        unowned let customer: Customer // Referencia no poseída
    
        init(number: Int, customer: Customer) {
            self.number = number
            self.customer = customer // Asignación segura en init
        }
        deinit { print("Tarjeta #\(number) está siendo destruida") }
    }
    
    var john: Customer? = Customer(name: "John Doe")
    john?.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)
    
    // Eliminar la referencia fuerte a Customer
    john = nil
    // Salida: "John Doe está siendo destruido", "Tarjeta #1234567890123456 está siendo destruida"
    // La referencia no poseída en CreditCard fue válida mientras existía customer.
    // Si CreditCard durara más que Customer y se intentara acceder a customer a través de la referencia no poseída, ocurriría un error.
    

Diferencia clave entre weak y unowned:

  • weak: el objeto puede ser nil. Úselo cuando la duración de los objetos no esté estrictamente relacionada (uno puede existir sin el otro).
  • unowned: el objeto no puede ser nil después de la inicialización. Úselo cuando esté seguro de que el objeto referenciado existirá al menos hasta que exista el objeto que hace referencia a él.