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
        }
    }
}