Middle+
Vždy je třeba používat weak nebo unowned v Capture List?
sobes.tech AI
Odpověď od AI
Ne, ne vždy.
weak a unowned se používají k prevenci silových cyklů (retain cycles) v uzávěrech, kdy uzávěr drží silnou referenci na objekt a objekt zase drží silnou referenci na uzávěr.
weak nebo unowned je třeba použít, když uzávěr zachytí silnou referenci na self nebo jiný referenční typ a existuje pravděpodobnost vzniku silového cyklu.
Situace, kdy není třeba používat weak/unowned:
- Uzávěr zachytí hodnotové typy (struktury, výčty, n-tice). Ty jsou při zachycení kopírovány a nevznikají cykly.
- Uzávěr zachytí referenční typ, ale neexistuje obousměrný silný odkaz. Například pokud je uzávěr vytvořen lokálně uvnitř metody a není uložen objektem, na který odkazuje.
- Uzávěr má krátkou životnost a bude vykonán dříve, než bude objekt, na který odkazuje, uvolněn. Například uzávěr předaný jako Completion Handler, který se ihned vykoná.
Volba mezi weak a unowned:
weak: používá se, když zachycený objekt může být kdykolinilpřed vykonáním uzávěru. Odkaz je volitelný (ObjectType?). Před použitím je třeba zkontrolovat nanil.unowned: používá se, když je známo, že zachycený objekt vždy bude existovat v době vykonání uzávěru. Odkaz není volitelný (ObjectType). Kontrola nanilnení potřeba. Použitíunownedu objektu, který se stalnil, povede k pádu (runtime error).
// Příklad, kdy není potřeba `weak`/`unowned` (zachycení struktury)
struct MyStruct {
var value: Int
}
let myStruct = MyStruct(value: 10)
let closure = {
print(myStruct.value) // kopie myStruct
}
closure()
// Příklad, kdy není potřeba `weak`/`unowned` (lokální uzávěr)
class MyClass {
func doSomething() {
let localValue = 5
let localClosure = {
print(self.description) // zachycuje self, ale uzávěr není uložen v MyClass
}
localClosure()
}
var description: String {
return "Instance of MyClass"
}
}
let myObject = MyClass()
myObject.doSomething()
// Příklad, kdy je potřeba `weak` (může být `nil`)
class AsyncOperation {
var completionHandler: (() -> Void)?
func performOperation() {
DispatchQueue.global().async {
print("Operace dokončena")
self.completionHandler?()
}
}
deinit {
print("AsyncOperation uvolněn")
}
}
class ViewController {
var op: AsyncOperation?
func setupOperation() {
op = AsyncOperation()
op?.completionHandler = { [weak self] in
guard let self = self else { return }
print("Completion handler ve ViewController: \(self)")
}
}
deinit {
print("ViewController uvolněn")
}
}
// Příklad, kdy je potřeba `unowned` (zaručeně existuje)
class Button {
var action: (() -> Void)?
func tap() {
action?()
}
deinit {
print("Button uvolněn")
}
}
class ViewControllerWithButton {
var button: Button
init() {
button = Button()
button.action = { [unowned self] in
print("Tlačítko stisknuto ve ViewControllerWithButton: \(self)")
}
}
deinit {
print("ViewControllerWithButton uvolněn")
}
}