Historique de la question :
L'analyse d'évasion est un terme provenant de l'optimisation des compilateurs et de la gestion de la mémoire. En Swift, il est important à cause de l'utilisation active des closures et de l'ARC. Il est lié aux concepts de closure d'évasion et de closure non-évasion, qui déterminent si les closures peuvent sortir du contexte de la fonction.
Problème :
Une mauvaise définition du type de closure entraîne des erreurs de possession de mémoire, des fuites, des captures inattendues de variables et une baisse de performance. Il est essentiel de comprendre clairement quand une closure "s'échappe" (escapes) ou non, et de les annoter correctement.
Solution :
Swift exige que les closures d'évasion soient explicitement marquées avec l'attribut @escaping. Les closures non-évasives peuvent seulement être capturées à l'intérieur de la fonction, elles bénéficient d'une gestion de mémoire plus efficace et peuvent utiliser les variables capturées de manière plus sûre.
Exemple de différence :
// closure non-évasive (plus rapide, ne reste pas en mémoire après l'appel) func performSync(block: () -> Void) { block() } // closure d'évasion (peut être enregistré et exécuté plus tard) var storedCompletion: (() -> Void)? func performAsync(block: @escaping () -> Void) { storedCompletion = block }
Caractéristiques clés :
Peut-on changer une closure définie comme non-évasive en closure d'évasion sans modifier le code source de la fonction ?
Non. L'attribut @escaping doit être explicitement indiqué dans la signature de la fonction. Si une closure à l'intérieur de la fonction est transmise à l'extérieur, seule une closure d'évasion est nécessaire, sinon le compilateur générera une erreur.
Est-il sûr de transmettre self à l'intérieur d'une closure d'évasion sans capture weak/unowned ?
Non. Une closure d'évasion peut potentiellement créer un cycle de rétention si elle capture self par une référence forte. Il est nécessaire de gérer explicitement la capture :
someAsync { [weak self] in self?.doSomething() }
Une closure d'évasion est-elle toujours globale (restée en mémoire jusqu'à la fin du programme) ?
Non. Son cycle de vie dépend de la portée de stockage. Si une closure est sauvegardée temporairement ou si sa propriété est annulée, elle sera libérée dès que la propriété perd son propriétaire. Seules celles qui portent des références à des objets globaux ou qui les stockent dans des variables globales deviennent globales.
Au sein d'une méthode de classe, une closure est sauvegardée sans @escaping (erreur de compilation), puis corrigée, oubliant de se prémunir contre le cycle de rétention — l'application fuit la mémoire.
Avantages :
Inconvénients :
Le développeur vérifie toujours où une closure d'évasion est nécessaire, capture self comme weak/unowned, évite les fuites, travaille avec la mémoire de manière sécurisée.
Avantages :
Inconvénients :