Swift可选转义闭包参数
鉴于: 有没有办法使Swift可选转义闭包参数,swift,function,closures,optional,Swift,Function,Closures,Optional,鉴于: 有没有办法使动作类型的完成参数(和动作)同时保持@转义 更改类型会导致以下错误: @转义属性仅适用于函数类型 删除@escaping属性后,代码将编译并运行,但似乎不正确,因为完成闭包正在转义函数的范围。有报告称@escaping未识别函数类型别名。这就是错误@转义属性仅适用于函数类型的原因。您可以通过展开函数签名中的函数类型来解决此问题: typealias Action = () -> () var action: Action = { } func doStuff(stu
动作类型的完成参数(和动作)同时保持@转义
更改类型会导致以下错误:
@转义属性仅适用于函数类型
删除@escaping
属性后,代码将编译并运行,但似乎不正确,因为完成
闭包正在转义函数的范围。有报告称@escaping
未识别函数类型别名。这就是错误@转义属性仅适用于函数类型的原因。您可以通过展开函数签名中的函数类型来解决此问题:
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()
编辑1::
我实际上是在一个xcode 8测试版下,这个bug还没有解决。修复了这个bug,引入了一个新的(你正在面对的)仍然开放的bug。看
临时解决方案@Michael Ilseman指出的解决方法是从可选函数类型中删除@escaping
属性,该属性将函数保持为escaping
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()
编辑2::
已关闭,明确说明参数位置中的闭包不是转义,需要用@escaping
标记它们以使其转义,但可选参数是隐式转义的,因为((Int)->())?
是可选()>
的同义词,可选的关闭正在从以下位置退出。
基本上,@转义仅在函数参数位置的闭包上有效。默认情况下,noescape规则仅适用于函数参数位置的这些闭包,否则它们将转义。聚合,例如具有关联值(例如,可选)的枚举、元组、结构等,如果它们具有闭包,则遵循不在函数参数位置的闭包的默认规则,即它们正在转义
所以可选函数参数默认为@escaping。
@noeascape默认情况下仅适用于函数参数。我遇到了类似的问题,因为混合使用@escaping
和非@escaping
非常容易混淆,尤其是当需要传递闭包时
最后,我通过={in}
为closure参数指定了一个no-op默认值,我认为这更有意义:
func doStuff(stuff: String, completion: Action?) {...}
我让它在Swift 3中工作,没有任何警告,只有这样:
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)
}
在本例中需要了解的重要一点是,如果将Action
更改为Action?
则闭包正在转义。那么,让我们按照你的建议做:
func doStuff(stuff: String, completion: (()->())? ) {
print(stuff)
action = completion
completion?()
}
好的,现在我们将调用doStuff
:
typealias Action = () -> ()
var action: Action? = { }
func doStuff(stuff: String, completion: Action?) {
print(stuff)
action = completion
completion?()
}
这个要求只适用于逃逸关闭。因此,关闭正在逃逸。这就是为什么不将其标记为转义-它已经转义了。现在获取@转义只能应用于函数类型func doStuff的参数(填充:String,completion:(@escaping()->())?){
一个临时解决方案是从可选函数类型中删除@escaping属性,该属性将函数保留为转义。
您能进一步解释一下吗?swift 3中的默认语义是非转义。虽然它编译时没有@escaping,但恐怕会被视为非转义而导致问题。这不是真的吗在进一步阅读中,我看到SR-2444说所有可选闭包都被视为转义,这是一个补充错误:)我假设当它被修复时,编译器会警告我们进行更改。可能有点离题;但是对于@autoclosure
,这是如何工作的?在那里会出现相同的错误…它在没有@es的情况下工作caping ufunc doStuff(stuff:String,completion:(()->())?){“删除@escaping
属性,代码编译并运行”-这是因为,如中所述,操作?
在默认情况下是转义的。因此,在使用可选闭包时删除@escaping
可以完成所需的操作。相关:。类型别名闭包是转义的。这里有一个描述发生此情况的原因以及一些解决方法,如果您希望可选参数为@noescape。这是干净的&很好的实现。如果我想检查这个块是否为nil/empty呢?糟糕,这对协议方法不起作用。“协议方法中不允许使用默认参数”(Xcode 8.3.2).我认为这为主题添加了最重要的信息,它应该是被接受的答案。合理的答案。这有多大可能会改变?这在技术上是有意义的,因为说(()->Void)“
等同于说你有OptionalVoid>
,为了让可选的
保持所有权,它只需要接受@escaping
函数。我想这应该是公认的答案。谢谢。嗨@matt,谢谢你的解释都是一样的?~func-foo(; closure:@escaping()->Void){}~func条(u闭包:(()->Void){}
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
}
}
}