Sobes.tech
Middle

Mindig szükséges weak vagy unowned használata a Capture List-ben?

sobes.tech MI

Válasz az MI-től

Nem, nem mindig.

A weak vagy unowned használata a Capture List-ben a retain ciklusok megelőzése érdekében.

A retain ciklus akkor fordul elő, amikor két vagy több objektum erősen hivatkozik egymásra, megakadályozva a memória felszabadítását.

A weak vagy unowned akkor szükséges, ha egy záradék erősen hivatkozik self-re (vagy más példányváltozóra az osztályban/aktorban), és viszont self (vagy más objektum) erős hivatkozással rendelkezik erre a záradékra.

Példák, amikor ez szükséges:

  • Aszinkron műveletek (hálózati kérések, adatok feldolgozása)
  • Observer mintázat
  • Animációs blokkok
  • Dispatch sorok

Ha a záradék nem foglalja el self-t (vagy más osztály/aktor változót, amely erős hivatkozással rendelkezik a záradékra), vagy strukturális típusokat/enumerációkat foglal magában, akkor a weak vagy unowned használata nem szükséges.

A weak és unowned közötti különbség:

Típus Leírás Mikor használjuk
weak Gyenge (opcionális) hivatkozás. nil lehet. Amikor a záradék életciklusa rövidebb vagy egyenlő a fogott objektum életciklusával, és az objektum nil lehet a záradék befejezése előtt.
unowned Nem fő (nem opcionális) hivatkozás. Nem lehet nil. Amikor a záradék életciklusa rövidebb vagy egyenlő a fogott objektum életciklusával, és garantált, hogy az objektum a záradék befejezése előtt létezik. Ha az objektum megszűnik a záradék végrehajtása előtt, akkor hibát okoz (unowned referencia a felszabadított példányra).

Példa a weak használatára a Capture List-ben:

class MyClass {
    var name: String = "Test"

    func performAsyncOperation() {
        DispatchQueue.global().async { [weak self] in
            guard let self = self else {
                return
            }
            print("Művelet befejeződött: \(self.name)")
        }
    }

    deinit {
        print("MyClass felszabadult")
    }
}

Példa az unowned használatára a Capture List-ben:

class ViewController {
    var dismissButton: UIButton!

    func setupButton() {
        dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
        // Ez a példa azt mutatja, hogy a `self` (ViewController) hosszabb vagy ugyanannyi ideig él, mint a gomb művelete.
        // A target-action nem záradék, de illusztrálja az unowned koncepciót erős hivatkozási ciklus esetén.
        // Ha ez záradék lenne, például UIControl.Event kezelőben,
        // és a ViewController garantáltan létezik a gomb megnyomásakor:
        // dismissButton.addAction(UIAction { [unowned self] _ in
        //     self.dismiss(animated: true, completion: nil)
        // }, for: .touchUpInside)
    }

    @objc func dismiss() {
        // Nézetvezérlő elvetése
    }
}

Ha a záradék nem hoz létre retain ciklust, a weak vagy unowned használata nem kötelező, és akár szükségtelen ellenőrzésekhez (a weak esetén) vagy potenciális hibákhoz (az unowned esetén) vezethet.

Például egy záradék, amely nem foglalja el self-t vagy más objektumot, amely erős hivatkozással rendelkezik a záradékra:

func fetchData(completion: @escaping (Data) -> Void) {
    URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
        guard let data = data else { return }
        // Itt nincs foglalás `self`-re vagy más objektumokra, amelyek ciklust okozhatnak.
        completion(data)
    }.resume()
}

Ebben az esetben [weak self] vagy [unowned self] a Capture List-ben nem szükséges.