Sobes.tech
Middle

Ar visada reikia naudoti weak arba unowned Capture sąraše?

sobes.tech AI

Atsakymas iš AI

Ne, ne visada.

Naudojame weak arba unowned Capture List'e, kad išvengtume retain cycle'ų.

Retain cycle'ai atsiranda, kai du ar daugiau objektų stipriai nurodo vienas kitą, neleidžiant atlaisvinti atminties.

Naudoti weak arba unowned reikia, kai užklausos užklausa stipriai nurodo self (ar kitą klasės/aktorės kintamąjį), ir savo ruožtu self (ar kitas objektas) turi stiprią nuorodą į šią užklausą.

Pavyzdžiai situacijų, kur tai būtina:

  • Asinchroninės operacijos (tinklo užklausos, duomenų apdorojimas)
  • Observer modelis
  • Animacijos blokai
  • Dispatch eilės

Jei užklausa nepaima self (ar kitą klasės/aktorės kintamąjį, kuris turi stiprią nuorodą į užklausą), arba paima struktūrinius tipus/arba sąrašus, weak arba unowned naudoti nereikia.

Skirtumas tarp weak ir unowned:

Tipas Aprašymas Kada naudoti
weak Silpna (pasirinktinė) nuoroda. Gali tapti nil. Kai užklausos gyvavimo ciklas trumpesnis arba lygus paimamo objekto gyvavimo ciklui, ir objektas gali tapti nil iki užklausos pabaigos.
unowned Nepriklausoma (pasirinktinė) nuoroda. Negali tapti nil. Kai užklausos gyvavimo ciklas trumpesnis arba lygus paimamo objekto gyvavimo ciklui, ir yra garantija, kad objektas egzistuos iki užklausos pabaigos. Jei objektas bus atlaisvintas iki užklausos vykdymo, įvyks klaida (unowned nuoroda į atlaisvintą objektą).

weak pavyzdys:

class MyClass {
    var name: String = "Test"

    func performAsyncOperation() {
        DispatchQueue.global().async { [weak self] in
            guard let self = self else {
                return
            }
            print("Operacija baigta \(self.name)")
        }
    }

    deinit {
        print("MyClass atlaisvintas")
    }
}

unowned pavyzdys:

class ViewController {
    var dismissButton: UIButton!

    func setupButton() {
        dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
        // Šiuo atveju, užklausa stipriai nurodo `self`.
        // Jei tai būtų užklausa, pavyzdžiui, UIControl.Event apdorotojui,
        // ir ViewController egzistuoja ilgiau arba lygiai tiek pat, kiek ir veiksmas:
        // dismissButton.addAction(UIAction { [unowned self] _ in
        //     self.dismiss(animated: true, completion: nil)
        // }, for: .touchUpInside)
    }

    @objc func dismiss() {
        // Atsikratyti vaizdo valdiklio
    }
}

Jei užklausa nesudaro retain cycle, weak arba unowned naudoti nereikia ir tai gali sukelti nereikalingas patikras (weak) arba potencialias klaidas (unowned).

Pavyzdžiui, užklausa, kuri nepaima self ar kitą objektą, kurio stipri nuoroda yra užklausoje:

func fetchData(completion: @escaping (Data) -> Void) {
    URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
        guard let data = data else { return }
        // Čia nėra `self` ar kitų objektų, kurie galėtų sukelti retain cycle.
        completion(data)
    }.resume()
}

Šiuo atveju [weak self] arba [unowned self] naudoti nereikia.