Sobes.tech
Middle

Czym jest unowned?

sobes.tech AI

Odpowiedź od AI

unowned — to słowo kluczowe w Swift do deklarowania słabej referencji. Używa się go, gdy dwa obiekty mają silny związek i ich cykle życia są od siebie zależne, ale chcemy uniknąć cyklicznych referencji, które mogą uniemożliwić zwolnienie pamięci.

Główne właściwości i różnice w stosunku do weak:

  • Nie opcjonalny: Referencja unowned nie będzie nil przez cały czas życia obiektu, do którego się odnosi.
  • Silny związek: Używa się go, gdy jeden obiekt posiada inny, i oba zawsze istnieją razem.
  • Podczas zwalniania: Jeśli obiekt, na który wskazuje referencja unowned, zostanie zwolniony z pamięci przed użyciem referencji, spowoduje to błąd w czasie działania (runtime error). Należy upewnić się, że obiekt, na który się odnosi, istnieje dłużej niż sama referencja.
  • Zastosowanie: Najczęściej używany dla delegatów, gdy delegat zawsze istnieje dłużej niż obiekt, który go wywołuje, lub w zamknięciach (closures), aby uniknąć cyklicznych referencji do self, gdy zamknięcie nie przechwytuje silnej referencji na self.

Przykład użycia w zamknięciu:

// swift
class MyClass {
    var name: String
    var closure: (() -> Void)?

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

    func setupClosure() {
        closure = { [unowned self] in // użycie unowned self
            print("Moje imię to \(self.name)")
        }
    }

    deinit {
        print("\(name) został zwolniony")
    }
}

Przykład użycia dla delegata (chociaż weak jest częściej używany dla delegatów, unowned jest również możliwy, jeśli delegat gwarantuje dłuższe życie):

// swift
protocol MyDelegate: AnyObject { // AnyObject wymaga typu referencyjnego
    func doSomething()
}

class DataSource {
    unowned var delegate: MyDelegate // referencja `unowned` do delegata

    init(delegate: MyDelegate) {
        self.delegate = delegate
    }

    func performAction() {
        delegate.doSomething()
    }

    deinit {
        print("DataSource został zwolniony")
    }
}

class MyController: MyDelegate {
    var dataSource: DataSource?

    override init() {
        super.init()
        dataSource = DataSource(delegate: self)
    }

    func doSomething() {
        print("Metoda delegata wywołana")
    }

    deinit {
        print("MyController został zwolniony")
    }
}

Wybór między weak a unowned zależy od tego, czy referencja jest opcjonalna i czy obiekt, na który się odnosi, istnieje gwarantowanie do końca życia referencji. Jeśli istnieje możliwość, że obiekt zostanie zwolniony przed użyciem referencji, należy użyć weak. Jeśli gwarancja istnienia jest zapewniona, a referencja nie powinna być opcjonalna, można użyć unowned.