J'ai la fonction suivante où j'ai un gestionnaire d'achèvement mais j'obtiens cette erreur:
Closure use of non-escaping parameter may allow it to escape
Voici mon code:
func makeRequestcompletion(completion:(_ response:Data, _ error:NSError)->Void) {
let urlString = URL(string: "http://someUrl.com")
if let url = urlString {
let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, urlRequestResponse, error) in
completion(data, error) // <-- here is I'm getting the error
})
task.resume()
}
}
L'un de vous sait pourquoi je reçois cette erreur?
J'apprécierai vraiment votre aide
Il semble que vous devez définir explicitement que la fermeture peut s'échapper.
À partir de Apple Developer docs ,
Une fermeture est censée échapper à une fonction lorsqu'elle est passée en argument à la fonction, mais elle est appelée après le retour de la fonction. Lorsque vous déclarez une fonction qui prend une fermeture comme l'un de ses paramètres, vous pouvez écrire @escaping avant le type du paramètre pour indiquer que la fermeture peut s'échapper.
TLDR; Ajouter le @escaping
mot-clé après la variable d'achèvement:
func makeRequestcompletion(completion: @escaping (_ response:Data, _ error:NSError)->Void) {
let urlString = URL(string: "http://someUrl.com")
if let url = urlString {
let task = URLSession.shared.dataTask(with: url, completionHandler: { (data, urlRequestResponse, error) in
completion(data, error) // <-- here is I'm getting the error
})
task.resume()
}
}
Une fermeture "d'échappement" est une fermeture qui peut survivre à l'étendue dans laquelle elle a été créée. Les fermetures d'échappement nécessitent une attention particulière concernant le comptage des références et la gestion de la mémoire et peuvent être plus difficiles à optimiser.
Avant Swift 3, la valeur par défaut des fermetures était de supposer qu'elles s'échappaient. Cela signifiait que les développeurs devaient identifier spécifiquement les fermetures connues pas pour s'échapper afin de permettre le compilateur pour faire des optimisations. La communauté a constaté qu'en fait, le compilateur pouvait facilement trouver par lui-même si une fermeture s'échappe ou non, et a décidé qu'une approche agressive de l'échappement pourrait entraîner un code plus rapide. Le résultat est que les fermetures sont maintenant supposé ne pas s'échapper, et vous devez signaler les fermetures qui s'échappent avec le @escaping
attribut.
Dans votre cas, la fermeture qui URLSession.shared.dataTask
accepte est lui-même une fermeture d'échappement, donc si vous utilisez une fermeture à l'intérieur, il doit également être marqué @escaping
.
@escaping
est contagieux pour toutes les méthodes d'appel, et le compilateur détermine quand vous devez l'inclure.
Considérez cet exemple (qui compile):
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: ()->()) {
dispatchNow(block)
}
func dispatchNow(_ block: ()->()) {
block()
}
Cependant, cet exemple modifié produit deux erreurs de type non-escaping parameter may allow it to escape
:
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: ()->()) {
dispatchLater(block)
}
func dispatchLater(_ block: ()->()) {
DispatchQueue.main.async(execute: block)
}
La répartition sur main signifie que la méthode dispatchLater
a besoin de @escaping
, et une fois que vous avez ajouté cela, la méthode dispatchSometime
aussi nécessite @escaping
pour l'exemple à compiler.
dispatchSometime( { print("Oh yeah") })
func dispatchSometime(_ block: @escaping ()->()) {
dispatchLater(block)
}
func dispatchLater(_ block: @escaping ()->()) {
DispatchQueue.main.async(execute: block)
}
Cependant, le plat à emporter est juste:
@escaping
jusqu'à la chaîne d'appel jusqu'à ce que le compilateur cesse de se plaindre.weak
avec les variables capturées car elles peuvent être conservées avec le bloc lui-même."Implications
Le cas vraiment amusant avec cela est où vous devez ajuster plusieurs méthodes pour inclure le @escaping
mot clé, ce qui empêche le compilateur de se plaindre. Cependant, si ces méthodes sont réellement conformes à un protocole, les méthodes de ce protocole doivent également obtenir le @escaping
mot clé, qui infecte également tous les autres conformants au protocole. Amusement!