【问题标题】:Swift optional escaping closureSwift 可选转义闭包
【发布时间】:2018-05-05 04:50:00
【问题描述】:

编译器错误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()
    }
}

但如果我将闭包设为可选,则不会出现编译器错误,这是为什么呢?函数返回后仍然可以调用闭包。

func sync(completion:(()->())?) {
    self.remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
        completion?()
    }
}

【问题讨论】:

标签: swift closures optional


【解决方案1】:

在 Optional 中包装闭包会自动将其标记为转义。它在技术上已经通过嵌入到枚举(可选)中“转义”了。

【讨论】:

  • 为什么会这样呢?这背后的想法是什么?
  • 令人着迷。我想这是因为,在包装器中被分配为属性值,它已经被转义了。
  • @matt 没错。如果你把一个闭包粘在一个结构中,它也会自动“转义”。
  • @matt 是的,我了解可选的工作原理,但这对我来说并不明显。很有趣!
  • 他们应该考虑使用第一句话作为错误信息。
【解决方案2】:

澄清:

为了理解这个案例,实现以下代码会很有用:

typealias completion = () -> ()

enum CompletionHandler {
    case success
    case failure

    static var handler: completion {
        get { return { } }
        set { }
    }
}

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

乍一看,这段代码似乎是合法的,但事实并非如此!你会得到编译时错误抱怨:

错误:分配非转义 参数 'handlerParameter' 到 @escaping 闭包

让 chObject = CompletionHandler.handler = handlerParameter

请注意:

注意:参数 'handlerParameter' 是隐式非转义函数 doSomething(handlerParameter: 完成) {

这是为什么呢?假设是代码sn-p与@escaping无关...

实际上,由于 Swift 3 已经发布,如果在 enumstructclass 中声明闭包,它会被“转义”默认。

作为参考,报告了与此问题相关的错误:

虽然他们可能不是 100% 与此案相关,但受让人的 cmets 清楚地描述了该案:

First comment:

这里的实际问题是 可选闭包是隐式的 @escaping 现在。

Second comment:

不幸的是,Swift 3 就是这种情况。这里是语义 在 Swift 3 中转义:

1) 函数参数位置的闭包是 默认不转义

2) 所有其他闭包都在逃逸

因此,所有泛型类型参数闭包,例如 Array 和 Optional,都在转义。

显然,Optional 是枚举。

同样——如上所述——同样的行为也适用于类和结构:

类案例:

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

上述两个代码 sn-ps 会导致相同的输出(编译时错误)。

为了解决这个问题,你需要让函数签名为

func doSomething( handlerParameter: @escaping completion)


回到主要问题:

由于您期望您必须让completion:(()->())? 被转义,这将自动完成-如上所述-。

【讨论】:

    猜你喜欢
    • 2017-01-29
    • 2021-12-20
    • 2017-01-23
    • 2020-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-31
    相关资源
    最近更新 更多