Closure escaping — c'est une closure qui "s'échappe" de la portée de la fonction appelante (par exemple, elle est enregistrée pour une exécution asynchrone).
Par défaut, en Swift, les fonctions acceptent des closures non-escaping : la closure est exécutée dans le cadre de l'appel de la fonction.
Pour indiquer explicitement une escaping, on utilise le mot-clé @escaping :
func asyncTask(completion: @escaping () -> Void) { DispatchQueue.main.async { completion() } }
Principales différences :
self dans une closure escaping, il faut indiquer explicitement [weak self] ou [unowned self] pour éviter les fuites de mémoire (retain cycle).Faut-il toujours écrire @escaping pour les closures passées en paramètres à une fonction appelant DispatchQueue.async ?
— Oui. Comme DispatchQueue.async conserve la closure jusqu'à son exécution, la closure devient escaping.
Exemple :
func foo(action: () -> Void) { DispatchQueue.main.async { action() // Ne compile pas : la closure doit être escaping. } } // Il faut : func bar(action: @escaping () -> Void) { ... }
Histoire
Le contrôleur a créé une référence forte à self à l'intérieur d'une closure escaping (par exemple, une requête réseau). Le contrôleur n'était pas libéré après avoir quitté l'écran — cycle de rétention fort. Solution : utiliser [weak self] ou [unowned self].
Histoire
La fonction a passé une closure à DispatchQueue.async, mais ne l'a pas marquée comme escaping. Le projet ne compilait pas, et les erreurs étaient difficiles à trouver à cause de la profondeur des fonctions.
Histoire
À l'intérieur de la closure, on accédait à un objet qui avait déjà été désinitialisé au moment de l'appel de la closure (utilisait [unowned self]). En conséquence — plantage à l'exécution. Solution : utiliser [weak self] et vérifier la valeur nulle.