Donné:
typealias Action = () -> ()
var action: Action = { }
func doStuff(stuff: String, completion: @escaping Action) {
print(stuff)
action = completion
completion()
}
func doStuffAgain() {
print("again")
action()
}
doStuff(stuff: "do stuff") {
print("Swift 3!")
}
doStuffAgain()
Est-il possible de créer le paramètre completion
(et action
) de type Action?
et de conserver également @escaping
?
Changer le type donne l'erreur suivante:
error: @escaping attribute only applies to function types
En supprimant l'attribut @escaping
, le code est compilé et exécuté, mais ne semble pas être correct car la fermeture de completion
échappe à la portée de la fonction.
Un SR-2552 indique que @escaping
ne reconnaît pas l'alias de type de fonction. c'est pourquoi l'erreur @escaping attribute only applies to function types
. vous pouvez contourner le problème en développant le type de fonction dans la signature de fonction:
typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: (@escaping ()->())?) {
print(stuff)
action = completion
completion?()
}
func doStuffAgain() {
print("again")
action?()
}
doStuff(stuff: "do stuff") {
print("Swift 3!")
}
doStuffAgain()
EDIT 1: :
J'étais actuellement sous une version bêta de xcode 8 où le bogue SR-2552 n'était pas encore résolu. en corrigeant ce bogue, en a introduit un nouveau (celui auquel vous faites face) qui est toujours ouvert. voir SR-2444 .
La solution de contournement @ Michael Ilseman indiquée comme solution temporaire consiste à supprimer l'attribut @escaping
du type de fonction facultatif, qui conserve la fonction en tant que s'échapper .
func doStuff(stuff: String, completion: Action?) {...}
EDIT 2: :
Le SR-2444 a été fermé indiquant explicitement que les fermetures dans les positions de paramètres ne s'échappent pas et nécessitent leur marquage avec @escaping
pour les échapper, mais les paramètres facultatifs échappent implicitement , puisque ((Int)->())?
est un synonyme de Optional<(Int)->()>
, les fermetures optionnelles s'échappent.
à partir de: liste de diffusion Swift-users
Fondamentalement, @escaping est valide uniquement sur les fermetures en position de paramètre de fonction. La règle noescape-by-default ne s'applique qu'à ces fermetures à la position du paramètre de la fonction, sinon elles s'échappent. Les agrégats, tels que les énumérations avec les valeurs associées (par exemple, facultative), les nuplets, les structures, etc., s'ils ont des fermetures, respectent les règles par défaut pour les fermetures qui ne sont pas à la position du paramètre de fonction, c'est-à-dire qu'elles s'échappent.
Donc, le paramètre de fonction facultatif est @escaping par défaut.
@ noeascape s'applique uniquement au paramètre de fonction par défaut.
je rencontre un problème similaire et parce que mélanger @ évacuer et non @ évacuer est très déroutant, surtout si vous devez faire passer les fermetures. Je me retrouve avec des paramètres par défaut (ce qui me semble plus logique)
func doStuff(stuff: String = "do stuff",
completion: @escaping (_ some: String) -> Void = { _ in }) {
completion(stuff)
}
doStuff(stuff: "bla") {
stuff in
print(stuff)
}
doStuff() {
stuff in
print(stuff)
}
Je l'ai fait fonctionner dans Swift 3 sans aucun avertissement uniquement de cette façon:
func doStuff(stuff: String, completion: (()->())? ) {
print(stuff)
action = completion
completion?()
}
La chose importante à comprendre dans l'exemple est que si vous changez Action
en Action?
, la fermeture s'échappe . Alors, faisons ce que vous proposez:
typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: Action?) {
print(stuff)
action = completion
completion?()
}
Bon, maintenant nous allons appeler doStuff
:
class ViewController: UIViewController {
var prop = ""
override func viewDidLoad() {
super.viewDidLoad()
doStuff(stuff: "do stuff") {
print("Swift 3!")
print(prop) // error: Reference to property 'prop' in closure
// requires explicit 'self.' to make capture semantics explicit
}
}
}
Eh bien, cette exigence ne se pose que pour échapper aux fermetures. Donc, la fermeture s'échappe. C'est pourquoi vous ne ( ne marquez pas cela s'échappant - cela s'échappe déjà.