Sobes.tech
Middle

¿Qué es unowned en el lenguaje Swift y cómo se usa?

sobes.tech AI

Respuesta de la IA

La referencia no poseída (posesión indirecta débil) en Swift se utiliza para evitar ciclos de posesión fuerte (retain cycles), cuando dos objetos se refieren mutuamente de manera fuerte, impidiendo su liberación de la memoria.

Características de unowned:

  • Garantiza que el objeto al que se refiere la referencia unowned siempre existe hasta el momento de usar esa referencia.
  • Si se intenta acceder a la referencia unowned después de que el objeto relacionado haya sido liberado, ocurrirá un error en tiempo de ejecución (runtime crash).
  • Se usa cuando el ciclo de vida del objeto que hace referencia no es más largo que el ciclo de vida del objeto al que se refiere. Es decir, la referencia con unowned no hace que el objeto sea fuerte.

Ejemplo de uso en captura de cierre:

class Customer {
    let name: String
    var card: CreditCard?

    init(name: String) {
        self.name = name
    }

    deinit {
        print("\(name) está siendo desalojado")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Referencia no poseída a Customer

    init(number: UInt64, customer: Customer) {
        self.number = number
        self.customer = customer
    }

    deinit {
        print("Tarjeta #\(number) está siendo desalojada")
    }
}

var john: Customer? // Customer opcional para permitir liberación
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

// Asignar nil a john llevará a liberar Customer y Card,
// ya que no hay ciclo de posesión fuerte
john = nil 

Otro ejemplo - uso de unowned en lista de captura de cierre:

class HTMLElement {
    let name: String
    let text: String?

    lazy var asHTML: () -> String = { [unowned self] in // Uso de unowned self
        if let text = self.text {
            return "<\(self.name)>\(text)</\(self.name)>"
        } else {
            return "<\(self.name) />"
        }
    }

    init(name: String, text: String? = nil) {
        self.name = name
        self.text = text
    }

    deinit {
        print("\(name) está siendo desalojado")
    }
}

var paragraph: HTMLElement? // Elemento HTML opcional
paragraph = HTMLElement(name: "p", text: "hola mundo")
print(paragraph!.asHTML())

// Asignar nil liberará HTMLElement, ya que la clausura no lo mantiene fuertemente
paragraph = nil

La elección entre unowned y weak depende de si la referencia puede ser nil durante la vida del objeto. Si la referencia nunca puede ser nil antes de que el objeto sea liberado, usa unowned. Si puede serlo, usa weak.