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 és az unowned a gyenge hivatkozási ciklusok (retain cycles) megelőzésére szolgálnak a záradékokban, ahol a záradék erős hivatkozást tart fenn egy objektumra, és az objektum viszont erős hivatkozást tart fenn a záradékra.

A weak vagy unowned használata szükséges, ha a záradék erős hivatkozást tart fenn self-re vagy más referenciális típusra, és fennáll a gyenge hivatkozási ciklus kialakulásának lehetősége.

Olyan helyzetek, amikor nem kell weak/unowned:

  • A záradék értéktípusokat (struktúrák, felsorolások, tuple-k) tart fenn. Ezek másolatként kerülnek átadásra, és nem alakulnak ki ciklusok.
  • A záradék referenciatípust tart fenn, de kétirányú erős hivatkozás nem létezik. Például, ha a záradék helyileg jön létre egy metódusban, és nem tárolja egy objektum.
  • A záradék rövid életű, és a rá hivatkozó objektum felszabadítása előtt végrehajtódik. Például, ha a záradék egy metódusban átadott Completion Handler, amely azonnal végrehajtódik.

A weak és unowned közötti választás:

  • weak: akkor használjuk, ha az igevett objektum bármikor nil-vé válhat a záradék végrehajtása előtt. Az hivatkozás opcionális (ObjectType?). nil ellenőrzése szükséges a használat előtt.
  • unowned: akkor használjuk, ha tudjuk, hogy az igevett objektum mindig létezik a záradék végrehajtásakor. Az hivatkozás nem opcionális (ObjectType). nil ellenőrzése nem szükséges. Az unowned használata olyan objektum esetén, amely nil-vé válik, runtime hibát eredményez.
// Példa, amikor nincs szükség `weak`/`unowned`-re (struktúra igevitel)
struct MyStruct {
    var value: Int
}

let myStruct = MyStruct(value: 10)
let closure = {
    print(myStruct.value) // másolatot vesz a myStruct-ről
}
closure()

// Példa, amikor nincs szükség `weak`/`unowned`-re (helyi záradék)
class MyClass {
    func doSomething() {
        let localValue = 5
        let localClosure = {
            print(self.description) // self-t  igevéli, de a záradék nem tárolódik a MyClass-ben
        }
        localClosure()
    }

    var description: String {
        return "MyClass példány"
    }
}

let myObject = MyClass()
myObject.doSomething()

// Példa, amikor `weak` szükséges (esetleg `nil`)
class AsyncOperation {
    var completionHandler: (() -> Void)?

    func performOperation() {
        DispatchQueue.global().async {
            print("Művelet befejeződött")
            self.completionHandler?()
        }
    }

    deinit {
        print("AsyncOperation felszabadult")
    }
}

class ViewController {
    var op: AsyncOperation?

    func setupOperation() {
        op = AsyncOperation()
        op?.completionHandler = { [weak self] in
            guard let self = self else { return }
            print("Completion handler a ViewController-ben: \(self)")
        }
    }

    deinit {
        print("ViewController felszabadult")
    }
}

// Példa, amikor `unowned` szükséges (biztosan létezik)
class Button {
    var action: (() -> Void)?

    func tap() {
        action?()
    }

    deinit {
        print("Button felszabadult")
    }
}

class ViewControllerWithButton {
    var button: Button

    init() {
        button = Button()
        button.action = { [unowned self] in
            print("Gomb megnyomva a ViewControllerWithButton-ben: \(self)")
        }
    }

    deinit {
        print("ViewControllerWithButton felszabadult")
    }
}