Sobes.tech
Middle

Czym jest unowned w języku Swift i jak się go używa?

sobes.tech AI

Odpowiedź od AI

Referencja nieposiadająca (słaba pośrednia własność) w Swift jest używana do unikania cykli silnego własności (retain cycles), gdy dwa obiekty odwołują się do siebie nawzajem w sposób silny, uniemożliwiając ich zwolnienie z pamięci.

Cechy unowned:

  • Gwarantuje, że obiekt, na który odnosi się referencja unowned, zawsze istnieje do momentu użycia tej referencji.
  • Jeśli spróbujesz uzyskać dostęp do referencji unowned po tym, jak powiązany obiekt został zwolniony, wystąpi błąd w czasie wykonywania (crash w czasie działania).
  • Używa się tego, gdy cykl życia obiektu odwołującego się nie jest dłuższy niż cykl życia obiektu, na który się odwołuje. Innymi słowy, referencja z unowned nie czyni obiektu silniejszym.

Przykład użycia w przechwytywaniu zamknięcia:

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

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

    deinit {
        print("\(name) jest wycofywany")
    }
}

class CreditCard {
    let number: UInt64
    unowned let customer: Customer // Referencja nieposiadana do Customer

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

    deinit {
        print("Karta #\(number) jest wycofywana")
    }
}

var john: Customer? // Opcjonalny Customer do zwolnienia
john = Customer(name: "John Appleseed")
john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)

// Przypisanie nil do john spowoduje zwolnienie Customer i Card,
// ponieważ nie ma cyklu silnego własności
john = nil 

Inny przykład - użycie unowned w liście przechwytywania zamknięcia:

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

    lazy var asHTML: () -> String = { [unowned self] in // Użycie 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) jest wycofywany")
    }
}

var paragraph: HTMLElement? // Opcjonalny element HTML
paragraph = HTMLElement(name: "p", text: "witaj świecie")
print(paragraph!.asHTML())

// Przypisanie nil zwolni HTMLElement, ponieważ zamknięcie nie trzyma go silnie
paragraph = nil

Wybór między unowned a weak zależy od tego, czy referencja może być nil podczas życia obiektu. Jeśli nigdy nie może stać się nil przed zwolnieniem obiektu, użyj unowned. Jeśli może, użyj weak.