web-dev-qa-db-fra.com

Mise à jour des fermetures sur Swift 3 - @escaping

J'ai mis à jour mon code vers Xcode 8.0 beta 6, mais je suis resté coincé avec ce qui semble être à propos du nouveau défaut de fermeture qui ne s'échappe pas. Dans le code suivant, Xcode suggère d'ajouter @escaping devant completion: sur la première ligne du code ci-dessous, mais cela ne compilera toujours pas et tournera en rond. *

(EDIT: En fait, @escaping devrait être ajouté dans aftercompletion:, comme le suggère Xcode. L'alerte peut toujours s'afficher, mais le nettoyage et la compilation supprimeront it.) * Comment ce code devrait-il être réécrit/corrigé pour fonctionner dans le Swiftmis à jour 3? J'ai jeté un coup d'œil dans le nouveau manuel, mais je n'ai pas trouvé d'échantillons de code appropriés.

func doSomething(withParameter parameter: Int, completion: () -> ()) {
    // Does something

    callSomeOtherFunc(withCompletion: completion)
  }

// Calling the method and execute closure 
doSomething(withParameter: 2) {
  // do things in closure
}

Toute aide très appréciée!

75
nontomatic

Swift 3: les attributs de paramètre de fermeture sont maintenant appliqués au paramètre type et non au paramètre lui-même

Avant Swift 3, les attributs de fermeture @autoclosure et @noescape étaient des attributs du paramètre de fermeture , mais sont maintenant des attributs. au paramètre type ; voir la proposition d'évolution acceptée Swift suivante:

Votre question spécifique concerne l'attribut de type de paramètre @escaping (auquel s'applique la même nouvelle règle), comme décrit dans la proposition acceptée Swift evolution pour laisser les paramètres de fermeture ne pas échapper par défaut:

Ces propositions sont désormais toutes deux implémentées dans la phase bêta de Xcode 8 (voir notes de version de Xcode 8 bêta 6 ; identifiant du compte dev. Nécessaire pour accéder).

Nouveauté de Xcode 8 beta 6 - Swift Compilateur: Swift Langue

Les paramètres de fermeture n'échappent pas par défaut, plutôt que d'être explicitement annotés avec @noescape. Utilisez @escaping pour indiquer qu’un paramètre de fermeture peut s’échapper. @autoclosure(escaping) est maintenant écrit en tant que @autoclosure @escaping. Les annotations @noescape et @autoclosure(escaping) sont obsolètes. (SE-0103)

...

Nouveauté de Xcode 8 beta - Swift et Apple Compilateurs LLVM: Swift Langue

Les attributs @noescape et @autoclosure doivent maintenant être écrits avant le type de paramètre et non avant le nom du paramètre. [SE-0049]

Par conséquent, vous utilisez l'attribut @escaping autre que par défaut comme suit; appliqué au type du paramètre de fermeture plutôt qu'au paramètre lui-même

func doSomething(withParameter parameter: Int, completion: @escaping () -> ()) {
    // ...
}

(y compris ma réponse à une question dans un commentaire voté ci-dessous, car les commentaires ne sont pas des données persistantes sous SO)

@Cristi Băluță: "Que fait l'échappement? Jamais vu ces mots-clés avant la conversion automatique de Swift3 ..."

Voir par exemple le lien vers le proposition d'évolution SE-0103 ci-dessus (ainsi que le texte cité des notes de version beta 6): auparavant, les paramètres de fermeture s'échappaient par défaut (il n'était donc pas nécessaire de l'existence d'un lien explicite). annotation pour échapper), mais sont maintenant à la place non échappées, par défaut. D'où l'ajout de @escaping pour annoter explicitement le fait qu'un paramètre de fermeture peut s'échapper (contrairement à son comportement par défaut). Cela explique également pourquoi @noescape est maintenant obsolète (inutile d'annoter le comportement par défaut).

Pour expliquer ce que cela signifie qu'un paramètre de fermeture s'échappe, je cite le Référence du langage - attributs :

"Appliquez cet attribut au type de paramètre dans une déclaration de méthode ou de fonction pour indiquer que la valeur du paramètre peut être stockée pour une exécution ultérieure. Cela signifie que la valeur est autorisée à dépasser la durée de vie de l'appel."

58
dfri

_@noescape_

De xcode 8 beta 6 @noescape est la valeur par défaut. Auparavant, @escaping était la valeur par défaut. Toute personne effectuant une mise à jour vers Swift 3.0 à partir de versions précédentes peut être confrontée à cette erreur.

Vous ne pouvez pas stocker une fermeture _@noescape_ dans une variable. Parce que si vous pouvez stocker une fermeture dans une variable, vous pouvez exécuter la fermeture à partir de n’importe où dans votre code. Mais _@noescape_ indique que le paramètre de fermeture ne peut pas échapper au corps de la fonction.

Cela donnera une erreur du compilateur dans Xcode 8

_class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: () -> ()) {
        myClosure = finishBlock    // ‼️ Error: Assigning non-escaping parameter 'finishBlock' to an @escaping closure
    }
}
_

Cela va compiler ok (écrire explicitement _@escaping_)

_class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: @escaping () -> ()) {
        myClosure = finishBlock
    }
}
_

Avantages de _@noescape_:

  • Le compilateur peut optimiser votre code pour de meilleures performances
  • Le compilateur peut s'occuper de la gestion de la mémoire
  • Il n'est pas nécessaire d'utiliser une faible référence à soi dans la fermeture


Pour plus de détails, consultez: Par défaut, les fermetures n'échappant pas

22
Warif Akhand Rishi