Sobes.tech
Middle

Qu'est-ce que unowned en Swift et comment l'utiliser?

sobes.tech IA

Réponse de l'IA

La référence non possédée (détention indirecte faible) en Swift est utilisée pour éviter les cycles de possession forte (cycles de rétention), lorsque deux objets se référencent mutuellement de manière forte, empêchant leur libération de la mémoire.

Caractéristiques de unowned :

  • Garantit que l'objet référencé par la référence unowned existe toujours jusqu'au moment de l'utilisation de cette référence.
  • Si l'on tente d'accéder à la référence unowned après que l'objet associé ait été libéré, une erreur d'exécution (crash à l'exécution) se produira.
  • Utilisé lorsque le cycle de vie de l'objet référant n'est pas plus long que celui de l'objet référencé. Autrement dit, la référence avec unowned ne rend pas l'objet plus fort.

Exemple d'utilisation dans une capture de clôture :

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

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

    deinit {
        print("\(name) est en train d'être désinitialisé")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Référence non possédée à Customer

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

    deinit {
        print("Carte #\(number) est en train d'être désinitialisée")
    }
}

var john: Customer? // Customer optionnel pour permettre la libération
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

// L'assignation de nil à john entraînera la libération de Customer et Card,
// car il n'y a pas de cycle de possession forte
john = nil 

Autre exemple - utilisation de unowned dans une liste de capture de clôture :

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

    lazy var asHTML: () -> String = { [unowned self] in // Utilisation 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 en train d'être désinitialisé")
    }
}

var paragraph: HTMLElement? // Élément HTML optionnel
paragraph = HTMLElement(name: "p", text: "bonjour le monde")
print(paragraph!.asHTML())

// La mise à nil libérera HTMLElement, car la clôture ne le retient pas fortement
paragraph = nil

Le choix entre unowned et weak dépend de si la référence peut être nil pendant la vie de l'objet. Si la référence ne peut jamais devenir nil avant la libération de l'objet, utilisez unowned. Si elle peut l'être, utilisez weak.