Middle+
Faut-il toujours utiliser weak ou unowned dans la liste de capture?
sobes.tech IA
Réponse de l'IA
Non, pas toujours.
Weak et unowned sont utilisés pour prévenir les cycles de références fortes (cycles de retention) dans les closures, lorsque la closure maintient une référence forte à un objet, et que l'objet maintient à son tour une référence forte à la closure.
Il est nécessaire d'utiliser weak ou unowned lorsque la closure capture une référence forte à self ou à un autre type référentiel, et qu'il existe une probabilité de cycle de références fortes.
Situations où il n'est pas nécessaire d'utiliser weak/unowned :
- La closure capture des types de valeur (structures, énumérations, tuples). Elles sont copiées lors de la capture, et aucun cycle de références fortes ne se produit.
- La closure capture un type référentiel, mais il n'existe pas de référence forte bidirectionnelle. Par exemple, si la closure est créée localement dans une méthode et n'est pas stockée dans un objet auquel elle fait référence.
- La closure a une durée de vie courte et s'exécutera avant que l'objet auquel elle fait référence ne soit libéré. Par exemple, une closure passée à une méthode en tant que gestionnaire de complétion qui s'exécute immédiatement.
Choix entre weak et unowned :
weak: utilisé lorsque l'objet capturé peut devenirnilà tout moment avant l'exécution de la closure. La référence est déclarée comme optionnelle (ObjectType?). Nécessite une vérification denilavant utilisation.unowned: utilisé lorsque l'on sait que l'objet capturé existera toujours au moment de l'exécution de la closure. La référence n'est pas optionnelle (ObjectType). Ne nécessite pas de vérification denil. Utiliserunownedpour un objet devenunilentraînera une erreur à l'exécution.
// Exemple où `weak`/`unowned` ne sont pas nécessaires (capture de structure)
struct MyStruct {
var value: Int
}
let myStruct = MyStruct(value: 10)
let closure = {
print(myStruct.value) // Capture une copie de myStruct
}
closure()
// Exemple où `weak`/`unowned` ne sont pas nécessaires (closure locale)
class MyClass {
func doSomething() {
let localValue = 5
let localClosure = {
print(self.description) // Capture self, mais la closure n'est pas stockée dans MyClass
}
localClosure()
}
var description: String {
return "Instance of MyClass"
}
}
let myObject = MyClass()
myObject.doSomething()
// Exemple où `weak` est nécessaire (potentiellement nil)
class AsyncOperation {
var completionHandler: (() -> Void)?
func performOperation() {
// Simulation de travail asynchrone
DispatchQueue.global().async {
print("Operation completed")
self.completionHandler?() // Chaînage optionnel
}
}
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")
}
}
// Exemple où `unowned` est nécessaire (existe toujours)
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")
}
}