简体   繁体   English

Swift可选的转义闭包

[英]Swift optional escaping closure

在此处输入图片说明

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. 编译器错误Closure use of non-escaping parameter 'completion' may allow it to escape ,这是有道理的,因为它将在函数返回后调用。

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?()
    }
}

Wrapping a closure in an Optional automatically marks it escaping. 将闭包包装在Optional中会自动将其转义。 It's technically already "escaped" by being embedded into an enum (the Optional). 从技术上讲,它已经被嵌入枚举(“可选”)“转义”了。

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: 您将收到编译时错误抱怨:

error : assigning non-escaping parameter 'handlerParameter' to an @escaping closure 错误 :将非转义参数'handlerParameter'分配给@转义闭包

let chObject = CompletionHandler.handler = handlerParameter 让chObject = CompletionHandler.handler = handlerParameter

with a note that: 注意:

note : parameter 'handlerParameter' is implicitly non-escaping func doSomething(handlerParameter: completion) { 注意 :参数'handlerParameter'是隐式非转义函数doSomething(handlerParameter:完成){

Why is that? 这是为什么? the assumption is that the code snippet has nothing to do with the @escaping ... 假设代码片段与@escaping没有@escaping ...

Actually, since Swift 3 has been released, the closure will be "escaped" if it's declared in enum , struct or class by default. 实际上,由于Swift 3已发布,因此默认情况下,如果在enumstructclass中声明了闭包,则闭包将被“转义”。

As a reference, there are bugs reported related to this issue: 作为参考,报告了与该问题有关的错误:

Although they might not 100% related to this case, the assignee comments are clearly describe the case: 尽管它们可能与本案并非100%相关,但受让人的评论清楚地描述了该案:

First comment : 第一条评论

The actual issue here is that optional closures are implicitly @escaping right now. 这里的实际问题是, 可选的闭包现在隐式@转义。

Second comment : 第二条评论

That is unfortunately the case for Swift 3. Here are the semantics for escaping in Swift 3: 不幸的是,Swift 3就是这种情况。这是Swift 3中转义的语义:

1) Closures in function parameter position are non-escaping by default 1)默认情况下,函数参数位置的闭包不转义

2) All other closures are escaping 2) 所有其他关闭都在逃逸

Thus, all generic type argument closures, such as Array and Optional , are escaping. 因此,所有通用类型参数闭包(例如Array和Optional )都在转义。

Obviously, Optional is enum. 显然, Optional是枚举。

Also -as mentioned above-, the same behavior would be applicable for the classes and structs: 同样-如上所述,相同的行为也适用于类和结构:

Class Case: 类案例:

typealias completion = () -> ()

class CompletionHandler {
    var handler: () -> ()

    init(handler: () -> ()) {
        self.handler = handler
    }
}

func doSomething(handlerParameter: completion) {
    let chObject = CompletionHandler(handler: handlerParameter)
}

Struct Case: 结构案例:

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). 上面的两个代码段将导致相同的输出(编译时错误)。

For fixing the case, you would need to let the function signature to be : 为了解决这个问题,您需要让函数签名为

func doSomething( handlerParameter: @escaping completion)


Back to the Main Question: 回到主要问题:

Since you are expecting that you have to let the completion:(()->())? 因为您期望您必须让completion:(()->())? to be escaped, that would automatically done -as described above-. 为了逃脱,这将自动完成-如上所述-。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM