xcode 将闭包更新为 Swift 3 - @escaping

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/39063499/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 18:20:34  来源:igfitidea点击:

Updating closures to Swift 3 - @escaping

xcodeescapingclosuresswift3

提问by nontomatic

I've updated my code to Xcode 8.0 beta 6 but I got stuck with what seems to be about the new non escaping closure default. In the following code Xcode suggests to add @escapingin front of completion:in the first line of the below code, but that still won't compile and goes in circles. *

我已经将我的代码更新到 Xcode 8.0 beta 6,但我被困在新的非转义闭包默认值上。在下面的代码中,Xcode 建议在下面代码的第一行@escaping前面添加completion:,但这仍然无法编译并循环。*

(EDIT: In fact, @escaping should be added in aftercompletion:, as Xcode suggests. The alert may still show but cleaning and compiling will remove it.)* How should this code be re-written / fixed to work in the updated Swift 3? I've had a look in the new manual but I couldn't find proper code samples.

编辑:事实上,@escaping 应该在之后添加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
}

Any help much appreciated!

非常感谢任何帮助!

采纳答案by dfri

Swift 3: closure parameter attributes are now applied to the parameter type, and not the parameter itself

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

Prior to Swift 3, the closure attributes @autoclosureand @noescapeused to be attributes to the closure parameter, but are now attributes to the parameter type; see the following accepted Swift evolution proposal:

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

Your specific question pertain to parameter type attribute @escaping(for which the same new rule applies), as described in the accepted Swift evolution proposal to let closure parameters be non-escaping by default:

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

These proposals are now both implemented in the beta stage of Xcode 8 (see release notes for Xcode 8 beta 6; dev. account login needed for access)

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

New in Xcode 8 beta 6 - Swift Compiler: Swift Language

Closure parameters are non-escaping by default, rather than explicitly being annotated with @noescape. Use @escapingto indicate that a closure parameter may escape. @autoclosure(escaping)is now written as @autoclosure @escaping. The annotations @noescapeand @autoclosure(escaping)are deprecated. (SE-0103)

...

New in Xcode 8 beta – Swift and Apple LLVM Compilers: Swift Language

The @noescapeand @autoclosureattributes must now be written before the parameter type instead of before the parameter name. [SE-0049]

Xcode 8 beta 6 新功能 - Swift Compiler: Swift Language

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

...

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

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

Hence, you use the non-default @escapingattribute as follows; applied to the typeof the closure parameter, rather than the parameter itself

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

func doSomething(withParameter parameter: Int, completion: @escaping () -> ()) {
    // ...
}


(Including my answer to a question in an upvoted comment below, as comments are not persistent data on SO)

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

@Cristi B?lu??: "What does escaping do? Never seen this keywords before swift3 auto-conversion ... "

@Cristi B?lu??:“转义有什么作用?在 swift3 自动转换之前从未见过这个关键字......”

See e.g. the link to the SE-0103 evolution proposal above(as well as the quoted text from the beta 6 release notes): previously, closure parameters were escaping by default (hence no need for the existence of an explicit annotation for escaping), but are now instead non-escaping, by default. Hence the addition of @escapingto explicitly annotate that a closure parameter may escape (contrary to its default behaviour). This also explains why @noescapeis now deprecated (no need to annotate the default behaviour).

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

For explaining what it means that a closure parameter is escaping, I quote the Language Reference - attributes:

为了解释闭包参数正在转义的含义,我引用了语言参考 - 属性

"Apply this attribute to a parameter's type in a method or function declaration to indicate that the parameter's value can be stored for later execution. This means that the value is allowed to outlive the lifetime of the call."

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

回答by Warif Akhand Rishi

@noescape

@noescape

From xcode 8 beta 6 @noescapeis the default. Prior to that, @escapingwas the default. Anybody updating to swift 3.0 from previous versions might face this error.

从 xcode 8 beta 6 开始@noescape是默认的。在此之前,@escaping是默认设置。从以前的版本更新到 swift 3.0 的任何人都可能面临此错误。

You can not store a @noescapeclosure inside a variable. Because if you can store a closure inside a variable, you can execute the closure from anywhere in your code. But @noescapestates that the closure parameter can not escape the body of the function.

您不能@noescape在变量中存储闭包。因为如果你可以在一个变量中存储一个闭包,你就可以在代码的任何地方执行这个闭包。但是@noescape声明闭包参数不能转义函数体。

This will give compiler error in Xcode 8

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

class MyClass {

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

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

This will compile ok (explicitly write @escaping)

这将编译正常(显式写入@escaping

class MyClass {

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

    func doSomething(finishBlock: @escaping () -> ()) {
        myClosure = finishBlock
    }
}

Benefits of @noescape:

好处@noescape

  • Compiler can optimize your code for better Performance
  • Compiler can take care of memory management
  • There is no need to use a weak reference to self in the closure
  • 编译器可以优化您的代码以获得更好的性能
  • 编译器可以负责内存管理
  • 没有必要在闭包中使用对 self 的弱引用


For details check out: Make non-escaping closures the default


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