Sobes.tech
Middle

Ce este unowned în limbajul Swift și cum se folosește?

sobes.tech AI

Răspuns de la AI

Referința ne deținută (gestionare indirectă slabă) în Swift este utilizată pentru a evita ciclurile de retenție puternice (retain cycles), atunci când două obiecte se referă reciproc în mod puternic, împiedicând eliberarea lor din memorie.

Caracteristici ale unowned:

  • Asigură că obiectul la care se face referire prin referința unowned existe întotdeauna până în momentul utilizării acestei referințe.
  • Dacă se încearcă accesarea referinței unowned după ce obiectul asociat a fost eliberat, va avea loc o eroare la timpul de execuție (runtime crash).
  • Se folosește atunci când ciclul de viață al obiectului care face referire nu este mai lung decât cel al obiectului la care se face referire. Cu alte cuvinte, referința cu unowned nu face ca obiectul să devină puternic.

Exemplu de utilizare în captarea unei închideri:

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

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

    deinit {
        print("\(name) este eliminat")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Referință ne deținută la Customer

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

    deinit {
        print("Card #\(number) este eliminat")
    }
}

var john: Customer? // Customer opțional pentru eliberare
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

// Atribuirea lui nil la john va duce la eliberarea lui Customer și Card,
// deoarece nu există un ciclu de retenție puternic
john = nil 

Alt exemplu - utilizarea unowned în lista de captare a unei închideri:

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

    lazy var asHTML: () -> String = { [unowned self] in // Utilizare 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) este eliminat")
    }
}

var paragraph: HTMLElement? // Element HTML opțional
paragraph = HTMLElement(name: "p", text: "salut lume")
print(paragraph!.asHTML())

// Atribuirea lui nil va elibera HTMLElement, deoarece închidere nu îl menține puternic
paragraph = nil

Alegerea între unowned și weak depinde de dacă referința poate fi nil în timpul vieții obiectului. Dacă referința nu poate deveni niciodată nil înainte de eliberarea obiectului, folosiți unowned. Dacă poate, folosiți weak.