将闭包更新到 Swift 3 - @escaping
Posted
技术标签:
【中文标题】将闭包更新到 Swift 3 - @escaping【英文标题】:Updating closures to Swift 3 - @escaping 【发布时间】:2016-12-28 01:24:13 【问题描述】:我已将我的代码更新到 Xcode 8.0 beta 6,但我被新的非转义闭包默认值所困扰。在下面的代码中,Xcode 建议在下面代码的第一行的completion:
前面添加@escaping
,但这仍然无法编译并循环往复。 *
(EDIT:事实上,@escaping 应该添加在 after 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
非常感谢任何帮助!
【问题讨论】:
【参考方案1】:Swift 3:闭包参数属性现在应用于参数type,而不是参数本身
在 Swift 3 之前,闭包属性 @autoclosure
和 @noescape
曾经是闭包参数的属性,但现在是参数type的属性;请参阅以下已接受的 Swift 进化提案:
您的具体问题与参数类型属性@escaping
(适用相同的新规则)有关,如已接受的 Swift 进化提案中所述,默认情况下让闭包参数不可转义:
这些提案现在都在 Xcode 8 的 beta 阶段实现(参见 release notes for 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 () -> ())
// ...
(包括我在下面的评论中对问题的回答,因为 cmets 不是 SO 上的持久数据)
@Cristi Băluță:“转义有什么作用?从未见过这个关键字 swift3自动转换前..."
参见例如SE-0103 evolution proposal above 的链接(以及 beta 6 发行说明中引用的文本):以前,闭包参数默认转义(因此不需要存在用于转义的显式注释),但现在不是- 转义,默认情况下。因此添加了@escaping
以明确注释闭包参数可能会逃逸(与其默认行为相反)。这也解释了为什么 @noescape
现在已被弃用(无需注释默认行为)。
为了解释闭包参数转义的含义,我引用Language Reference - attributes:
"将此属性应用于方法或函数声明中的参数类型,以指示参数的值可以存储为 稍后执行。这意味着允许该值比 调用的生命周期。”
【讨论】:
感谢 dfri 的彻底回答。我实际上确实在参数之前的正确位置添加了@escaping,我只是注意到我的错误在描述中指出了这一点。 Xcode 仍然会像我描述的那样抱怨,但是无论如何进行清理和编译最终都会删除警报。 @nontomatic 很乐意为您提供帮助。 转义有什么作用?在 swift3 自动转换之前从未见过这个关键字,我认为我没有丢失任何东西。 @CristiBăluță 参见例如上面SE-0103 evolution proposal的链接(以及beta 6发行说明中引用的文本):以前,闭包参数默认转义(因此不需要注释它们正在转义),但现在不是逃脱。因此添加了@escaping
以明确注释关闭参数可能会逃逸(与其默认行为相反)。这也解释了为什么 @noescape
未被弃用(无需注释默认行为)。
@SagarR.Kothari 问题和答案都基于我们知道转义和非转义闭包之间的区别这一事实,因此我之前对 CristiBăluță 的评论(回答 为什么这个关键字现在存在)。为了解释它的作用,我引用了 lang。 ref.: "将此属性应用于方法或函数声明中的参数类型,以指示可以存储参数的值以供以后执行。这意味着允许该值超过调用的生命周期。".【参考方案2】:
@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
这样就可以编译了(显式写@escaping
)
class MyClass
var myClosure: (() -> ())?
func doSomething(finishBlock: @escaping () -> ())
myClosure = finishBlock
@noescape
的好处:
详情请查看:Make non-escaping closures the default
【讨论】:
以上是关于将闭包更新到 Swift 3 - @escaping的主要内容,如果未能解决你的问题,请参考以下文章