Swift可选的转义闭包 [英] Swift optional escaping closure
问题描述
编译器错误Closure use of non-escaping parameter 'completion' may allow it to escape
,之所以有意义,是因为它将在函数返回后被调用.
Compiler error Closure use of non-escaping parameter 'completion' may allow it to escape
, Which make sense because it will be called after the function return.
func sync(completion:(()->())) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion()
}
}
但是,如果我将闭包设置为可选,则不会出现编译器错误,这是为什么呢?函数返回后仍可以调用闭包.
But if I make closure optional then no compiler error, Why is that? closure can still be called after the function returns.
func sync(completion:(()->())?) {
self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
completion?()
}
}
推荐答案
说明:
为了理解这种情况,实现以下代码将很有用:
Clarification:
For understanding the case, implementing the following code would be useful:
typealias completion = () -> ()
enum CompletionHandler {
case success
case failure
static var handler: completion {
get { return { } }
set { }
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler.handler = handlerParameter
}
乍看之下,这段代码似乎合法,但事实并非如此!您会收到编译时错误提示:
At the first look, this code seems to be legal, but it's not! you would get compile-time error complaining:
错误:分配非转义 参数'handlerParameter'到一个@转义的闭包
error: assigning non-escaping parameter 'handlerParameter' to an @escaping closure
让chObject = CompletionHandler.handler = handlerParameter
let chObject = CompletionHandler.handler = handlerParameter
,并带有以下说明:
注释:参数'handlerParameter'是隐式的非转义函数 doSomething(handlerParameter:完成){
note: parameter 'handlerParameter' is implicitly non-escaping func doSomething(handlerParameter: completion) {
那是为什么?假设代码段与@escaping
...
Why is that? the assumption is that the code snippet has nothing to do with the @escaping
...
实际上,由于Swift 3已发布,如果闭包在 enum , struct 或 class 中声明,则闭包将被转义"默认.
Actually, since Swift 3 has been released, the closure will be "escaped" if it's declared in enum, struct or class by default.
作为参考,报告了与该问题有关的错误:
As a reference, there are bugs reported related to this issue:
- Optional closure type is always considered @escaping.
- @escaping failing on optional blocks.
尽管它们可能与本案并非100%相关,但受让人的评论清楚地描述了该案:
Although they might not 100% related to this case, the assignee comments are clearly describe the case:
这里的实际问题是可选的闭包是隐式的 @立即转义.
The actual issue here is that optional closures are implicitly @escaping right now.
不幸的是,Swift 3就是这种情况. 在Swift 3中逃脱
That is unfortunately the case for Swift 3. Here are the semantics for escaping in Swift 3:
1)函数参数位置的闭包为 默认情况下不转义
1) Closures in function parameter position are non-escaping by default
2)所有其他闭包都在转义
因此,所有通用类型参数闭包(例如Array和 Optional )都在转义.
Thus, all generic type argument closures, such as Array and Optional, are escaping.
很明显,Optional
是枚举.
Obviously, Optional
is enum.
同样-如上所述,相同的行为也适用于类和结构:
Also -as mentioned above-, the same behavior would be applicable for the classes and structs:
课堂案例:
typealias completion = () -> ()
class CompletionHandler {
var handler: () -> ()
init(handler: () -> ()) {
self.handler = handler
}
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
结构案例:
typealias completion = () -> ()
struct CompletionHandler {
var handler: completion
}
func doSomething(handlerParameter: completion) {
let chObject = CompletionHandler(handler: handlerParameter)
}
以上两个代码段将导致相同的输出(编译时错误).
The two above code snippets would leads to the same output (compile-time error).
要解决此问题,您需要使函数签名为:
func doSomething( handlerParameter: @escaping completion)
由于您期望必须让completion:(()->())?
转义,所以会自动完成-如上所述-.
Since you are expecting that you have to let the completion:(()->())?
to be escaped, that would automatically done -as described above-.
这篇关于Swift可选的转义闭包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!