Sobes.tech
Middle+

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

sobes.tech AI

Vastus AI-lt

Ei, mitte alati.

Weak ja unowned kasutatakse tugevate viidete tsüklite (retain cycles) vältimiseks suletud plokkides, kui plokk hoiab tugeva viite objekti vastu ja objekt omakorda hoiab tugeva viite plokki.

weak või unowned tuleb kasutada, kui plokk haarab tugeva viite self-le või teisele viidetüübile ning on tõenäoline, et tekib tugevate viidete tsükkel.

Situatsioonid, kus ei ole vaja kasutada weak/unowned:

  • Plokk haarab väärtusetüübid (struktuurid, loendused, paarid). Need kopeeritakse haaramisel ning tugevate viidete tsüklid ei teki.
  • Plokk haarab viidetüübi, kuid ei ole kahepoolselt tugevat viidet. Näiteks, kui plokk luuakse kohapeal meetodis ja seda ei salvestata objektile, millele see viitab.
  • Plokk on lühiajaline ning täidetakse enne objekti vabastamist, millele see viitab. Näiteks, plokk, mis antakse edasi meetodile kui Completion Handler ja täidetakse kohe.

Valik weak ja unowned vahel:

  • weak: Kasutatakse, kui haaratud objekt võib muutuda nil-iks igal ajal enne ploki täitmist. Viide on opcionalne (ObjectType?). Vajab nil-kontrolli enne kasutamist.
  • unowned: Kasutatakse, kui on teada, et haaratud objekt alati eksisteerib ploki täitmise ajal. Viide ei ole opcionalne (ObjectType). Ei vaja nil-kontrolli. unowned kasutamine objekti jaoks, mis muutub nil-iks, põhjustab jooksuaegse vea.
// Näide, kui ei ole vaja weak/unowned (struktuuri haaramine)
struct MyStruct {
    var value: Int
}

let myStruct = MyStruct(value: 10)
let closure = {
    print(myStruct.value) // haarab myStruct koopiat
}
closure()

// Näide, kui ei ole vaja weak/unowned (kohalik plokk)
class MyClass {
    func doSomething() {
        let localValue = 5
        let localClosure = {
            print(self.description) // haarab self, kuid plokk ei salvestata MyClass-ile
        }
        localClosure()
    }

    var description: String {
        return "Instance of MyClass"
    }
}

let myObject = MyClass()
myObject.doSomething()

// Näide, kui on vaja weak (võib muutuda nil-iks)
class AsyncOperation {
    var completionHandler: (() -> Void)?

    func performOperation() {
        // Asünkroonne töö
        DispatchQueue.global().async {
            print("Operation completed")
            self.completionHandler?() // nil-opcional chaining
        }
    }

    deinit {
        print("AsyncOperation deinitialized")
    }
}

class ViewController {
    var op: AsyncOperation?

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

    deinit {
        print("ViewController deinitialized")
    }
}

// Näide, kui on vaja unowned (garantii olemasolu)
class Button {
    var action: (() -> Void)?

    func tap() {
        action?()
    }

    deinit {
        print("Button deinitialized")
    }
}

class ViewControllerWithButton {
    var button: Button

    init() {
        button = Button()
        button.action = { [unowned self] in // unowned self
            print("Button tapped in ViewControllerWithButton: \(self)")
        }
    }

    deinit {
        print("ViewControllerWithButton deinitialized")
    }
}