Middle+
Vždy je potrebné použiť weak alebo unowned v Capture List?
sobes.tech AI
Odpoveď od AI
Nie, nie vždy.
weak a unowned sa používajú na prevenciu silových cyklov (retain cycles) v uzávierkach, keď uzávierka drží silnú referenciu na objekt a objekt zase drží silnú referenciu na uzávierku.
weak alebo unowned je potrebné použiť, ak uzávierka zachytí silnú referenciu na self alebo iný referenčný typ a existuje pravdepodobnosť vzniku silového cyklu.
Situácie, keď nie je potrebné používať weak/unowned:
- Uzávierka zachytí hodnotové typy (štruktúry, enumy, tuple). Tie sa kopírujú pri zachytení a nevznikajú cykly silových referencií.
- Uzávierka zachytí referenčný typ, ale neexistuje obojsmerný silný cyklus. Napríklad, ak je uzávierka vytvorená lokálne v metóde a nie je uložená objektom, na ktorý odkazuje.
- Uzávierka má krátky život a bude vykonaná skôr, ako bude objekt, na ktorý odkazuje, uvoľnený. Napríklad, uzávierka odovzdaná ako Completion Handler, ktorá sa okamžite vykoná.
Voľba medzi weak a unowned:
weak: používa sa, keď zachytený objekt môže byť kedykoľveknilpred vykonaním uzávierky. Odkaz je ako voliteľný (ObjectType?). Vyžaduje sa kontrola nanilpred použitím.unowned: používa sa, keď je známe, že zachytený objekt vždy bude existovať v čase vykonania uzávierky. Odkaz nie je voliteľný (ObjectType). Kontrola nanilnie je potrebná. Použitieunownedu objektu, ktorý sa stalnil, povedie k pádu (runtime error).
// Príklad, keď nie je potrebné `weak`/`unowned` (zachytenie štruktúry)
struct MyStruct {
var value: Int
}
let myStruct = MyStruct(value: 10)
let closure = {
print(myStruct.value) // kopíruje myStruct
}
closure()
// Príklad, keď nie je potrebné `weak`/`unowned` (lokálne uzávier)
class MyClass {
func doSomething() {
let localValue = 5
let localClosure = {
print(self.description) // zachytáva self, ale uzávier sa neukladá v MyClass
}
localClosure()
}
var description: String {
return "Inštancia MyClass"
}
}
let myObject = MyClass()
myObject.doSomething()
// Príklad, keď je potrebné `weak` (môže byť `nil`)
class AsyncOperation {
var completionHandler: (() -> Void)?
func performOperation() {
DispatchQueue.global().async {
print("Operácia dokončená")
self.completionHandler?()
}
}
deinit {
print("AsyncOperation uvoľnený")
}
}
class ViewController {
var op: AsyncOperation?
func setupOperation() {
op = AsyncOperation()
op?.completionHandler = { [weak self] in
guard let self = self else { return }
print("Completion handler vo ViewController: \(self)")
}
}
deinit {
print("ViewController uvoľnený")
}
}
// Príklad, keď je potrebné `unowned` (zaručene existuje)
class Button {
var action: (() -> Void)?
func tap() {
action?()
}
deinit {
print("Button uvoľnený")
}
}
class ViewControllerWithButton {
var button: Button
init() {
button = Button()
button.action = { [unowned self] in
print("Tlačidlo stlačené vo ViewControllerWithButton: \(self)")
}
}
deinit {
print("ViewControllerWithButton uvoľnený")
}
}