Considérez cette classe :
class A {
var closure: (() -> Void)?
func someMethod(closure: @escaping () -> Void) {
self.closure = closure
}
}
someMethod
attribue la fermeture passée en paramètre à une propriété de la classe.
Maintenant voici une autre classe :
class B {
var number = 0
var a: A = A()
func anotherMethod() {
a.someMethod { self.number = 10 }
}
}
Si j'appelle anotherMethod
, la fermeture { self.number = 10 }
sera stockée dans l'instance de A
. Comme self
est capture dans la fermeture, l'instance de A
aura également une référence forte à cela.
C'est essentiellement un exemple de fermeture échappée !
Vous vous demandez probablement, "quoi ? Donc où la fermeture s'échappe-t-elle, et vers où ?"
La fermeture s'échappe du scope de la méthode, vers le scope de la classe. Et elle peut être appelée plus tard, même sur un autre thread ! Cela pourrait poser des problèmes s'il n'est pas géré correctement.
Par défaut, Swift n'autorise pas aux fermetures d'échapper. Vous devez ajouter @escaping
au type de fermeture pour dire au compilateur "Veuillez permettre à cette fermeture de s'échapper". Si nous supprimons @escaping
:
class A {
var closure: (() -> Void)?
func someMethod(closure: () -> Void) {
}
}
et essayons d'écrire self.closure = closure
, cela ne compile pas !
4 votes
Pour citer le manuel, « Une fermeture est dite échapper à une fonction lorsqu'elle est passée en argument à la fonction, mais est appelée après que la fonction retourne ». Donc, si la fermeture est appelée de manière synchrone, elle est non-échappante. Un exemple pourrait être une fermeture d'énumération, ou les méthodes fonctionnelles
map
,filter
, etc. Si elle est appelée de manière asynchrone (c'est-à-dire plus tard), elle est échappante. L'exemple le plus courant de fermeture échappante serait le gestionnaire de fin d'une tâche asynchrone lente, comme une requête réseau.1 votes
Si vous pensez que ma réponse répond à votre question, veuillez considérer l'accepter en cliquant sur cette coche.