Sobes.tech
Middle

Kas alati on vaja kasutada weak või unowned Capture listis?

sobes.tech AI

Vastus AI-lt

Ei, mitte alati.

Kasutame weak või unowned Capture List'is, et vältida retain cycle'e.

Retain cycle'id tekivad, kui kaks või enam objekti tugevalt viitavad üksteisele, takistades mälu vabastamist.

weak või unowned kasutamine on vajalik, kui sulgemine tugevalt viitab self (või teisele klassi/aktiivi muutuja), ning omakorda self (või teine objekt) omab tugevat viidet sellele sulgemisele.

Näited olukordadest, kus see on vajalik:

  • Asünkroonilised operatsioonid (võrgu päringud, andmete töötlemine)
  • Observer muster
  • Animatsiooniblokid
  • Dispatch järjekorrad

Kui sulgemine ei haarata self-i (või teist klassi/aktiivi muutuja, millel on tugev viide sulgemisele), või haarab struktuurseid tüüpe/loendeid, siis weak või unowned kasutamine ei ole vajalik.

weak ja unowned erinevus:

Tüüp Kirjeldus Millal kasutada
weak Nõrk (valikuline) viide. Võib muutuda nil-iks. Kui sulgemise elutsükkel on lühem või võrdne haaratud objekti elutsükliga ning objekt võib muutuda nil-iks enne sulgemise lõppu.
unowned Mitte-omandav (valikuline mitte) viide. Ei saa muutuda nil-iks. Kui sulgemise elutsükkel on lühem või võrdne haaratud objekti elutsükliga ning on garanteeritud, et objekt eksisteerib kuni sulgemise lõpuni. Kui objekt vabastatakse enne sulgemise täitmist, tekib viga (unowned viide deallocated instance'ile).

weak näide:

class MyClass {
    var name: String = "Test"

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

    deinit {
        print("MyClass vabastatud")
    }
}

unowned näide:

class ViewController {
    var dismissButton: UIButton!

    func setupButton() {
        dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
        // Antud juhul, sulgemine haarab `self`-i.
        // Kui see oleks sulgemine, näiteks UIControl.Event töötlejas,
        // ja ViewController eksisteerib kauem või sama kaua kui tegevus:
        // dismissButton.addAction(UIAction { [unowned self] _ in
        //     self.dismiss(animated: true, completion: nil)
        // }, for: .touchUpInside)
    }

    @objc func dismiss() {
        // Vaadeldava kontrolli sulgemine
    }
}

Kui sulgemine ei loo retain cycle'i, siis weak või unowned kasutamine ei ole vajalik ning võib isegi põhjustada tarbetuid kontrollimisi (weak) või potentsiaalseid vigu (unowned).

Näide, kui sulgemine ei haarata self-i või teist objekti, millel on tugev viide sulgemisele:

func fetchData(completion: @escaping (Data) -> Void) {
    URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
        guard let data = data else { return }
        // Siin ei haarata `self`-i ega teisi objekte, mis võiksid põhjustada retain cycle'i.
        completion(data)
    }.resume()
}

Selles olukorras [weak self] või [unowned self] ei ole vajalik.