function - valvula - Parámetro de cierre de escape opcional Swift 3
valvula de escape definicion (5)
Hay un
SR-2552
que informa que
@escaping
no reconoce el alias de tipo de función.
Es por eso que el
@escaping attribute only applies to function types
error
@escaping attribute only applies to function types
.
puede solucionarlo expandiendo el tipo de función en la firma de la función:
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()
EDITAR 1 ::
En realidad, estaba bajo una versión beta de xcode 8 donde el error SR-2552 aún no se había resuelto. arreglando ese error, introduje uno nuevo (el que estás enfrentando) que todavía está abierto. ver SR-2444 .
La solución alternativa que
@Michael Ilseman
señaló como una solución temporal es eliminar el atributo
@escaping
del tipo de función opcional,
que mantiene la función como escape
.
func doStuff(stuff: String, completion: Action?) {...}
EDITAR 2 ::
El
SR-2444
se ha cerrado indicando explícitamente que los cierres en las posiciones de parámetros
no
escapan y necesitan marcarse con
@escaping
para que escapen, pero los parámetros opcionales escapan implícitamente, ya que
((Int)->())?
es un sinónimo de
Optional<(Int)->()>
, se están escapando los cierres opcionales.
Dado:
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()
¿Hay alguna forma de hacer el parámetro de
completion
(y
action
) de tipo
Action?
y también sigo
@escaping
?
Cambiar el tipo da el siguiente error:
error: @escaping attribute only applies to function types
Al eliminar el atributo
@escaping
, el código se compila y se ejecuta, pero no parece ser correcto ya que el cierre de la
completion
escapa al alcance de la función.
Lo hice funcionar en Swift 3 sin ninguna advertencia solo de esta manera:
func doStuff(stuff: String, completion: (()->())? ) {
print(stuff)
action = completion
completion?()
}
Lo importante para entender en el ejemplo es que si cambia
Action
por
Action?
El cierre se
está
escapando.
Entonces, hagamos lo que propongas:
typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: Action?) {
print(stuff)
action = completion
completion?()
}
Bien, ahora llamaremos a
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
}
}
}
Bueno, ese requisito solo surge para escapar de los cierres. Entonces el cierre se está escapando. Es por eso que no lo marca como un escape, ya está escapando.
Me encuentro con un problema similar y porque mezclar @escaping y no @escaping es muy confuso, especialmente si necesita pasar los cierres. Termino con los parámetros predeterminados (que creo que tiene más sentido)
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)
}
de: lista de correo de usuarios rápidos
Básicamente, @escaping es válido solo en cierres en la posición del parámetro de función. La regla de noescape-by-default solo se aplica a estos cierres en la posición del parámetro de función, de lo contrario se están escapando. Los agregados, como las enumeraciones con valores asociados (por ejemplo, opcionales), tuplas, estructuras, etc., si tienen cierres, siguen las reglas predeterminadas para los cierres que no están en la posición del parámetro de función, es decir, están escapando.
Entonces, el parámetro de función opcional es @escaping por defecto.
@noeascape solo se aplica al parámetro de función de forma predeterminada.