47 votes

Échapper les fermetures en Swift

Je suis nouveau en Swift et je lisais le manuel quand j'ai rencontré les fermetures d'échappement. Je n'ai pas du tout compris la description du manuel. Est-ce que quelqu'un pourrait s'il vous plaît m'expliquer ce que sont les fermetures d'échappement en Swift en termes simples.

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.

2voto

yoAlex5 Points 2350

non-escaping(@noescape) vs escaping(@escaping) closure

[Fonction et fermeture]

fermeture non-échappante

@noescape est une fermeture qui est passée dans une fonction et qui est appelée avant que la fonction ne retourne

Un bon exemple de fermeture non-échappante est la fonction sort du Array - sorted(by: (Element, Element) -> Bool). Cette fermeture est appelée pendant l'exécution des calculs de tri.

Histoire : @noescape a été introduit dans Swift 2 -> a été obsolète dans Swift 3 où il est devenu un défaut, c'est pourquoi vous devez marquer explicitement l'attribut @escaping.

func foo(_ nonEscapingClosure: () -> Void) {
    nonEscapingClosure()
}

fermeture échappante

//`@escaping` aide à corriger
La fermeture échappante capture un paramètre non-échappant

@escaping est une fermeture qui est

  1. passée dans une fonction
  2. La fonction propriétaire enregistre cette fermeture dans une propriété
  3. la fermeture est appelée(utilisant la propriété) après que la fonction propriétaire retourne(asynchrone)

Un bon exemple d'une fermeture échappante est un gestionnaire de complétion dans une opération asynchrone. Si vous ne marquez pas votre fonction avec @escaping dans ce cas, vous obtenez une erreur de compilation. Faire référence à une propriété dans une fermeture échappante nécessite que vous utilisiez self de manière explicite

class MyClass {
    var completionHandler: (() -> Void)?

    func foo(_ escapingClosure: @escaping () -> Void) {

        //si vous ne marquez pas avec @escaping vous obtenez
        //Assignation du paramètre non-échappant 'escapingClosure' à une fermeture échappante
        completionHandler = escapingClosure //<- erreur ici
    }

    func onEvent() {
        completionHandler?()
    }
}

[Synchrone vs Asynchrone]

2voto

zeytin Points 4200

Définition de l'évasion

Les fermetures de Swift sont des types de référence, ce qui signifie que si vous pointez deux variables sur la même fermeture, elles partagent cette fermeture - Swift se contente de se souvenir qu'il y a deux choses qui en dépendent en incrémentant son compteur de référence.

Lorsqu'une fermeture est passée dans une fonction pour être utilisée, Swift doit savoir si cette fonction sera utilisée immédiatement ou si elle sera enregistrée pour une utilisation ultérieure. Si elle est utilisée immédiatement, le compilateur peut éviter d'ajouter un à son compteur de référence car la fermeture sera exécutée immédiatement puis oubliée. Mais si elle est utilisée plus tard - ou même pourrait être utilisée plus tard - Swift doit ajouter un à son compteur de référence pour éviter qu'elle ne soit accidentellement détruite.

Exemple rapide

Un bon exemple d'une fermeture s'échappant est un gestionnaire de complétion. Il est exécuté dans le futur, lorsqu'une tâche longue est terminée, donc il survit à la fonction dans laquelle il a été créé. Un autre exemple est la programmation asynchrone : une fermeture qui est exécutée de manière asynchrone s'échappe toujours de son contexte d'origine.

public func responseData(
    queue: DispatchQueue? = nil,
    completionHandler: @escaping (DataResponse) -> Void)
    -> Self
{
    ...

Informations supplémentaires

Pour des raisons de performance, Swift suppose que toutes les fermetures sont des fermetures non s'échappant, ce qui signifie qu'elles seront utilisées immédiatement à l'intérieur de la fonction et non stockées, ce qui signifie à son tour que Swift ne touche pas au compteur de référence. Si ce n'est pas le cas - si vous prenez des mesures pour stocker la fermeture - alors Swift vous forcera à la marquer comme @escaping afin que le compteur de références doit être modifié.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X