假设:
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()
有没有办法制作completion
action
类型参数(和Action?
)并保留@escaping
?
更改类型会出现以下错误:
error: @escaping attribute only applies to function types
删除@escaping
属性,代码编译并运行,但似乎不正确,因为completion
闭包正在逃避函数的范围。
答案 0 :(得分:180)
基本上,@ escaping仅对函数参数位置的闭包有效。 noescape-by-default规则仅适用于函数参数位置的这些闭包,否则它们将被转义。聚合,例如具有关联值的枚举(例如可选),元组,结构等,如果它们具有闭包,则遵循不在函数参数位置的闭包的默认规则,即它们正在转义。
因此默认情况下,可选的函数参数是@escaping @noeascape默认仅适用于函数参数。
答案 1 :(得分:100)
有SR-2552报告@escaping
无法识别函数类型别名。这就是错误@escaping attribute only applies to function types
的原因。您可以通过扩展函数签名中的函数类型来解决此问题:
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()
编辑1::
我实际上是在xcode 8 beta版本下,其中错误SR-2552尚未解决。修复那个bug,引入了一个新的(你正面临的那个)仍然是开放的。见SR-2444。
解决方法 @Michael Ilseman 指出作为临时解决方案是从可选功能类型中移除@escaping
属性,使函数保持转义。
func doStuff(stuff: String, completion: Action?) {...}
编辑2::
SR-2444已被关闭,明确说明参数位置中的闭包不是转义,需要用@escaping
标记它们以使它们转义,但可选参数 隐式转义,因为((Int)->())?
是Optional<(Int)->()>
的同义词,可选闭包正在转义。
答案 2 :(得分:15)
我遇到类似的问题,因为混合@escaping和非@escaping非常混乱,特别是如果你需要传递闭包。我最终得到了默认参数(我认为这更有意义)
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)
}
答案 3 :(得分:15)
我只是通过这种方式在没有任何警告的情况下在Swift 3中工作:
func doStuff(stuff: String, completion: (()->())? ) {
print(stuff)
action = completion
completion?()
}
答案 4 :(得分:1)
该示例中要理解的重要一点是,如果将testImageBuild
更改为Action
,闭包将会转义。所以,让我们按照您的建议进行操作:
Action?
好的,现在我们叫typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: Action?) {
print(stuff)
action = completion
completion?()
}
:
doStuff
好吧,该要求仅适用于转义闭包。所以关闭是逃避。这就是为什么您不标记转义-它已经转义了。