Je vždy nutné používat weak nebo unowned v seznamu zachycení?
sobes.tech AI
Odpověď od AI
Ne, ne vždy.
Používáme weak nebo unowned v Capture List k prevenci cyklů udržování.
Cyklus udržování vzniká, když si dva nebo více objektů navzájem silně odkazují, což brání uvolnění paměti.
Použití weak nebo unowned je nutné, když uzávěr silně odkazuje na self (nebo jinou proměnnou instance třídy/aktora), a naopak self (nebo jiný objekt) má silnou referenci na tento uzávěr.
Příklady situací, kdy je to nutné:
- Asynchronní operace (síťové požadavky, zpracování dat)
- Vzor pozorovatele
- Animační bloky
- Dispatch fronty
Pokud uzávěr nezachytává self (nebo jinou proměnnou třídy/aktora, která má silnou referenci na uzávěr), nebo zachytává strukturální typy/enumerace, použití weak nebo unowned není nutné.
Rozdíl mezi weak a unowned:
| Typ | Popis | Kdy použít |
|---|---|---|
weak |
Slabá (volitelná) reference. Může být nil. |
Když je životní cyklus uzávěru kratší nebo roven životnímu cyklu zachyceného objektu, a objekt může být nil před dokončením uzávěru. |
unowned |
Nezávislá (nevolitelná) reference. Nemůže být nil. |
Když je životní cyklus uzávěru kratší nebo roven životnímu cyklu zachyceného objektu, a je garantováno, že objekt bude existovat do dokončení uzávěru. Pokud objekt před dokončením uzávěru zmizí, dojde k pádu (unowned reference na deallocovanou instanci). |
Příklad použití weak v Capture List:
class MyClass {
var name: String = "Test"
func performAsyncOperation() {
DispatchQueue.global().async { [weak self] in
guard let self = self else {
return
}
print("Operace dokončena pro \(self.name)")
}
}
deinit {
print("MyClass uvolněn")
}
}
Příklad použití unowned v Capture List:
class ViewController {
var dismissButton: UIButton!
func setupButton() {
dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
// Tento příklad ukazuje, že `self` (ViewController) žije déle nebo stejně dlouho jako akce tlačítka.
// Target-action není uzávěr, ale ilustruje koncept unowned v případě silného cyklu udržování.
// Pokud by to byla uzávěr, například v handleru UIControl.Event,
// a ViewController existuje zaručeně během stisknutí tlačítka:
// dismissButton.addAction(UIAction { [unowned self] _ in
// self.dismiss(animated: true, completion: nil)
// }, for: .touchUpInside)
}
@objc func dismiss() {
// Zavření view controlleru
}
}
Pokud uzávěr nezpůsobí cyklus udržování, použití weak nebo unowned není nutné a může dokonce vést k zbytečným kontrolám (v případě weak) nebo potenciálním pádům (v případě unowned).
Například uzávěr, který nezachytává self nebo jiný objekt, na který má uzávěr silnou referenci:
func fetchData(completion: @escaping (Data) -> Void) {
URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
guard let data = data else { return }
// Zde není zachycení `self` nebo jiných objektů, které by mohly způsobit cyklus udržování.
completion(data)
}.resume()
}
V tomto případě není [weak self] nebo [unowned self] v Capture List nutné.