更新Swift 3的闭包 - @escaping

non*_*tic 75 xcode closures escaping swift3

我已经将我的代码更新为Xcode 8.0 beta 6,但我似乎陷入了关于新的非转义关闭默认值的问题.在下面的代码中,Xcode建议在下面代码的第一行@escaping前面添加completion:,但是仍然不会编译并进入圆圈.*

(编辑:事实上,@scaping应该在之后 添加completion:,正如Xcode建议的那样.警报可能仍然显示,但清理和编译将删除它.)*如何重新编写/修复此代码以在更新的Swift 3中工作?我看过新手册,但找不到合适的代码示例.

func doSomething(withParameter parameter: Int, completion: () -> ()) {
    // Does something

    callSomeOtherFunc(withCompletion: completion)
  }

// Calling the method and execute closure 
doSomething(withParameter: 2) {
  // do things in closure
}
Run Code Online (Sandbox Code Playgroud)

任何帮助非常感谢!

dfr*_*fri 58

Swift 3:闭包参数属性现在应用于参数类型,而不是参数本身

在Swift 3之前,闭包属性@autoclosure并且@noescape曾经是闭包参数的属性,但现在属于参数类型 ; 请参阅以下接受的Swift进化建议:

您的具体问题与参数类型属性@escaping(适用相同的新规则)有关,如接受的Swift演进提议中所述,默认情况下允许闭包参数不转义:

这些提议现在都在Xcode 8的beta阶段实现(请参阅Xcode 8 beta 6的发行说明 ;访问所需的开发帐户登录)

Xcode 8 beta 6中的新功能 - Swift编译器:Swift语言

默认情况下,闭包参数是非转义的,而不是显式注释@noescape.使用@escaping以指示关闭参数可以逃脱.@autoclosure(escaping)现在写成 @autoclosure @escaping.注释@noescape@autoclosure(escaping)不推荐使用.(SE-0103)

...

Xcode 8 beta中的新功能 - Swift和Apple LLVM编译器:Swift语言

@noescape@autoclosure属性现在必须在参数名前的参数类型前,而不是被写入.[SE-0049]

因此,您使用非默认@escaping属性,如下所示; 应用于闭包参数的类型,而不是参数本身

func doSomething(withParameter parameter: Int, completion: @escaping () -> ()) {
    // ...
}
Run Code Online (Sandbox Code Playgroud)

(包括我在下面的评论中对问题的回答,因为评论不是关于SO的持久性数据)

@CristiBăluţă:"逃避的是什么?在swift3自动转换之前从未见过这个关键字......"

请参阅上面SE-0103演化提案的链接(以及beta 6发行说明中的​​引用文本):之前,默认情况下,闭包参数是转义的(因此不需要存在用于转义的显式注释),但默认情况下现在是非转义的.因此,添加@escaping显式注释闭包参数可能会转义(与其默认行为相反).这也解释了为什么@noescape现在已弃用(无需注释默认行为).

为了解释闭包参数转义是什么意思,我引用语言参考 - 属性:

"将此属性应用于方法或函数声明中的参数类型,以指示可以存储参数的值以供以后执行.这意味着允许该值超过调用的生命周期."

  • 逃避是做什么的?在swift3自动转换之前从未见过这个关键字,我不认为我失去了任何东西. (7认同)
  • @ SagarR.Kothari问题和答案的基础是我们知道转义和非转换闭包之间的区别,因此我之前对CristiBăluţă的评论(答案_why_此关键字现在存在).为了解释它的作用,我引用了lang.ref.:""将此属性应用于方法或函数声明中的参数类型,以指示可以存储参数的值以供稍后执行.这意味着允许该值超过调用的生命周期."_. (3认同)

War*_*shi 22

@noescape

从xcode 8 beta 6 @noescape是默认值.在此之前,@escaping是默认值.任何人从以前的版本更新到swift 3.0可能会遇到此错误.

您不能@noescape在变量中存储闭包.因为如果可以在变量中存储闭包,则可以从代码中的任何位置执行闭包.但是@noescape声明闭包参数无法逃脱函数体.

这将在Xcode 8中产生编译器错误

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: () -> ()) {
        myClosure = finishBlock    // ?? Error: Assigning non-escaping parameter 'finishBlock' to an @escaping closure
    }
}
Run Code Online (Sandbox Code Playgroud)

这将编译好(显式写@escaping)

class MyClass {

    var myClosure: (() -> ())?

    func doSomething(finishBlock: @escaping () -> ()) {
        myClosure = finishBlock
    }
}
Run Code Online (Sandbox Code Playgroud)

好处@noescape:

  • 编译器可以优化您的代码以获得更好的性能
  • 编译器可以处理内存管理
  • 在闭包中不需要使用弱引用


有关详细信息,请查看:将非转义闭包设为默认值