[英]Swift optional escaping closure parameter
鉴于:
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()
有什么方法可以制作Action?
类型的completion
参数(和action
) Action?
并保持@escaping
?
更改类型会出现以下错误:
@escaping 属性仅适用于函数类型
删除@escaping
属性,代码编译并运行,但似乎不正确,因为completion
闭包正在转义函数的范围。
来自: swift-users 邮件列表
基本上,@escaping 仅对函数参数位置的闭包有效。 noescape-by-default 规则仅适用于函数参数位置的这些闭包,否则它们将被转义。 聚合体,例如带有关联值的枚举(例如 Optional)、元组、结构体等,如果它们有闭包,那么对于不在函数参数位置的闭包,即它们是转义的,遵循默认规则。
所以可选的函数参数默认是@escaping。
@noeascape 默认仅适用于函数参数。
有一个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尚未解决。 修复该错误,引入了一个仍处于打开状态的新错误(您面临的错误)。 见SR-2444 。
@Michael Ilseman指出的临时解决方法是从可选函数类型中删除@escaping
属性,使函数保持为 escaping 。
func doStuff(stuff: String, completion: Action?) {...}
编辑2 ::
该SR-2444已经被关闭,说明明确,在参数关闭位置不逃逸,需要他们被打上@escaping
让他们逃脱,但可选参数隐含逃脱,因为((Int)->())?
是Optional<(Int)->()>
的同义词,可选闭包正在转义。
我遇到了类似的问题,因为混合@escaping
和非@escaping
非常令人困惑,特别是如果您需要传递闭包。
我最终通过= { _ in }
为闭包参数分配了一个无操作默认值,我认为这更有意义:
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)
}
我让它在 Swift 3 中工作,没有任何警告,只有这样:
func doStuff(stuff: String, completion: (()->())? ) {
print(stuff)
action = completion
completion?()
}
在示例中要理解的重要一点是,如果将Action
更改为Action?
关闭正在逃脱。 所以,让我们按照你的建议去做:
typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: Action?) {
print(stuff)
action = completion
completion?()
}
好的,现在我们将调用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
}
}
}
嗯,这个要求只出现在转义闭包中。 所以关闭正在逃逸。 这就是为什么你没有将它标记为转义 - 它已经在转义了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.