Sobes.tech
Middle

Cos'è unowned nel linguaggio Swift e come si usa?

sobes.tech AI

Risposta dell'AI

Il riferimento non posseduto (gestione indiretta debole) in Swift viene utilizzato per evitare cicli di possesso forte (retain cycles), quando due oggetti si riferiscono reciprocamente in modo forte, impedendo il loro rilascio dalla memoria.

Caratteristiche di unowned:

  • Garantisce che l'oggetto a cui si riferisce la referenza unowned esista sempre fino al momento dell'uso di questa referenza.
  • Se si tenta di accedere alla referenza unowned dopo che l'oggetto associato è stato rilasciato, si verificherà un errore in fase di esecuzione (runtime crash).
  • Viene usato quando il ciclo di vita dell'oggetto che fa riferimento non è più lungo di quello dell'oggetto a cui si riferisce. In altre parole, la referenza con unowned non rende l'oggetto più forte.

Esempio di utilizzo in una cattura di closure:

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

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

    deinit {
        print("\(name) viene deallocato")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Referenza non posseduta a Customer

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

    deinit {
        print("Carta #\(number) viene deallocata")
    }
}

var john: Customer? // Customer opzionale per consentire la liberazione
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

// Assegnare nil a john porterà alla liberazione di Customer e Card,
// poiché non c'è ciclo di possesso forte
john = nil 

Un altro esempio - utilizzo di unowned in una lista di cattura di closure:

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

    lazy var asHTML: () -> String = { [unowned self] in // Uso di 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) viene deallocato")
    }
}

var paragraph: HTMLElement? // Elemento HTML opzionale
paragraph = HTMLElement(name: "p", text: "ciao mondo")
print(paragraph!.asHTML())

// Assegnare nil libererà HTMLElement, poiché la closure non lo mantiene forte
paragraph = nil

La scelta tra unowned e weak dipende dal fatto che la referenza possa essere nil durante la vita dell'oggetto. Se la referenza non può mai diventare nil prima che l'oggetto venga deallocato, usa unowned. Se può, usa weak.