当前位置: 首页 > 面试题库 >

Swift可选的转义闭包

糜淇
2023-03-14
问题内容

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

问题答案:

Clarification:

为了理解这种情况,实现以下代码将很有用:

typealias completion = () -> ()

enum CompletionHandler {
    case success
    case failure

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

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

乍一看,此代码似乎合法,但事实并非如此!您会收到
编译时错误抱怨:

error : assigning non-escaping parameter ‘handlerParameter’ to an
@escaping closure

let chObject = CompletionHandler.handler = handlerParameter

with a note that:

note : parameter ‘handlerParameter’ is implicitly non-escaping func
doSomething(handlerParameter: completion) {

这是为什么?假设是代码段已无关的@escaping…

实际上,由于Swift 3已发布,如果默认在enum,struct或class中声明了闭包,则闭包将被“转义” 。

As a reference, there are bugs reported related to this issue:

  • 可选的闭包类型始终被视为@escaping。.
  • @转义在可选块上失败。.

尽管它们可能与本案并非100%相关,但受让人的评论
清楚地描述了该案:

First
comment:

The actual issue here is that optional closures are implicitly @escaping
right now.

Second
comment:

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

1)默认情况下,函数参数位置的闭包不转义

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

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

Obviously,Optional is enum.

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

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:

既然你期待,你必须让completion:(()->())?被逃脱,会自动完成-as上面描述。



 类似资料:
  • 问题内容: 鉴于: 有什么方法可以使参数(和)的类型也保持不变? 更改类型会出现以下错误: @escaping属性仅适用于函数类型 删除该属性后,代码将编译并运行,但由于闭包使函数的作用范围变大,因此似乎并不正确。 问题答案: 有一个SR-2552报告无法识别功能类型别名。这就是错误的原因。您可以通过扩展函数签名中的函数类型来解决: 编辑1 : 我实际上是在xcode 8 beta版本下,但尚未解

  • 鉴于: 有什么方法可以使类型的参数(和)并且还保留? 更改类型会产生以下错误: @escaping属性仅适用于函数类型 删除属性,代码将编译并运行,但似乎不正确,因为闭包正在转义函数的范围。

  • 编译器错误,这是有意义的,因为它将在函数返回后调用。 但如果我将闭包设置为可选的,那么没有编译器错误,这是为什么?在函数返回后仍然可以调用闭包。

  • 我有一个,其形式为: 但是我得到错误:< code >将非转义参数“someOtherClosure”传递给需要@escaping闭包的函数。 这两个闭包实际上都是不可转义的(默认情况下),并且显式地将添加到会产生一个警告,表明这是Swift 3.1中的默认值。 知道我为什么会得到这个错误吗?

  • 问题内容: 我是Swift的新手,当我遇到转义的闭包时,我正在阅读手册。我根本没有得到手册的描述。有人可以简单地向我解释一下Swift中的转义闭包是什么。 问题答案: 考虑此类: 将传入的闭包分配给类中的属性。 现在是另一个类: 如果我调用,则闭包将存储在的实例中。由于是在闭包中捕获的,因此的实例还将对其具有很强的引用性。 基本上,这是逃脱的闭包的例子! 您可能想知道,“什么?那么封闭从何处逃脱到

  • 我知道Swift 3中的更改,其中@nonevinging是闭包的默认行为。 我已经成功地更改了有关更改的大部分代码,但我的代码中有一部分无法摆脱闭包使用非转义参数可能允许它转义编译错误。 我尝试过在updateHandler参数和UpdatedInProgressHandler typealias中添加@逃逸,但这似乎还不够。 有人能帮我找出问题的原因吗? 定义typealiases和函数的代码