Moet je altijd weak of unowned gebruiken in de Capture List?
sobes.tech AI
Antwoord van AI
Nee, niet altijd.
We gebruiken weak of unowned in de Capture List om retain cycles te voorkomen.
Een retain cycle ontstaat wanneer twee of meer objecten elkaar sterk verwijzen, waardoor het geheugen niet vrijgegeven kan worden.
Gebruik weak of unowned wanneer een closure sterk verwijst naar self (of een andere instantievariabele van een klasse/actor), en self (of een ander object) een sterke verwijzing heeft naar die closure.
Voorbeelden van situaties waarin dit nodig is:
- Asynchrone operaties (netwerkverzoeken, gegevensverwerking)
- Observer patroon
- Animatieblokken
- Dispatch queues
Als de closure self (of een andere variabele van klasse/actor die een sterke verwijzing heeft naar de closure) niet vastlegt, of structurele types/enumeraties vastlegt, is het gebruik van weak of unowned niet nodig.
Verschillen tussen weak en unowned:
| Type | Beschrijving | Wanneer gebruiken |
|---|---|---|
weak |
Zwakke (optionele) verwijzing. Kan nil worden. |
Wanneer de levenscyclus van de closure korter of gelijk is aan die van het vastgelegde object, en het object nil kan worden vóór het einde van de closure. |
unowned |
Onopvallende (niet-optionele) verwijzing. Kan niet nil worden. |
Wanneer de levenscyclus van de closure korter of gelijk is aan die van het vastgelegde object, en gegarandeerd wordt dat het object zal bestaan tot het einde van de closure. Als het object vóór de uitvoering van de closure wordt vrijgegeven, treedt een crash op (unowned referentie naar gedealloceerde instantie). |
Voorbeeld van gebruik van weak in Capture List:
class MyClass {
var name: String = "Test"
func performAsyncOperation() {
// Closure vastlegt `self`.
// MyClass kan worden vrijgegeven voordat de asynchrone operatie is voltooid.
DispatchQueue.global().async { [weak self] in
guard let self = self else {
// `self` is vrijgegeven, uitgaan
return
}
print("Operatie voltooid voor \(self.name)")
}
}
deinit {
print("MyClass gedealloceerd")
}
}
Voorbeeld van gebruik van unowned in Capture List:
class ViewController {
var dismissButton: UIButton!
func setupButton() {
dismissButton.addTarget(self, action: #selector(dismiss), for: .touchUpInside)
// Closure vastlegt `self`.
// We gaan ervan uit dat `self` (ViewController) langer leeft of even lang als de actie van de knop.
// In dit geval is de target-actie geen closure, maar illustreert het het concept van `unowned` bij sterke referentiecyclus.
// Als dit *een* closure was, bijvoorbeeld in een UIControl.Event-handler,
// en ViewController bestaat tijdens de klik:
// dismissButton.addAction(UIAction { [unowned self] _ in
// self.dismiss(animated: true, completion: nil)
// }, for: .touchUpInside)
}
@objc func dismiss() {
// ViewController sluiten
}
}
Als de closure geen retain cycle vormt, is het gebruik van weak of unowned niet nodig en kan het zelfs leiden tot onnodige controles (weak) of potentiële crashes (unowned).
Bijvoorbeeld, een closure die self of een ander object niet vastlegt, dat een sterke verwijzing heeft naar de closure:
func fetchData(completion: @escaping (Data) -> Void) {
URLSession.shared.dataTask(with: URL(string: "...")!) { data, response, error in
guard let data = data else { return }
// Hier wordt `self` of andere objecten niet vastgelegd, wat een retain cycle voorkomt.
completion(data)
}.resume()
}
In dit geval zijn [weak self] of [unowned self] in de Capture List niet nodig.