【问题标题】:How to call non-escaping closure inside a local closure? [duplicate]如何在本地闭包中调用非转义闭包? [复制]
【发布时间】:2016-10-16 17:00:59
【问题描述】:

我有一个看起来像这样的函数:

func test(closure: () -> ()) {
    let localClosure = { closure() }

    localClosure()
}

这只是一个例子,并不能完全反映我遇到的问题,显然这里我可以直接调用closure

应该清楚,在上面的代码中,closure 不能转义。但是,我得到了错误:

闭包使用非转义参数'closure'可能会允许它转义

现在,如果localClosure 以某种方式逃逸,我会理解这个错误,但它不会逃逸。我什至尝试将localClosure 注释为@noescape(即使该属性在 Swift 3 中已被弃用),并且根据我收到的警告:

@noescape 是 默认值,已弃用

如果localClosure 默认情况下是非转义的,那么为什么另一个非转义闭包不能进入其中呢?或者这是编译器的错误/限制?

【问题讨论】:

  • 可能相关的问答(至少 w.r.t 编译器关于 localClosure 默认为 @noescape 的虚假警告,但事实并非如此):Why do closures require an explicit self when they're all non-escaping by default in Swift 3?
  • @Hamish 我相信目标线程实际上是该线程的完美欺骗标记(即使这是一个稍微不同的问题,目标的答案也回答了这个问题):整个讨论(和以前答案)一旦明确默认情况下非参数闭包实际上是@escaping,那么一个简单的事实就崩溃了。投票欺骗标记!
  • @dfri 嗯....实际上考虑一下,我同意 - 鉴于答案基本上是“localClosure 实际上是@escaping,目前没有(非弃用) 将其标记为非转义的方式".

标签: swift closures swift3


【解决方案1】:

非参数闭包默认为@escaping

“如果localClosure 默认情况下是非转义的,那么为什么...”

根据以下 cmets 中的讨论(感谢@Hamish),我们可以陈述以下关于 Swift 3.0 中非参数闭包的事实

  • 默认情况下,它们是@escaping,与人们可能认为的相反。由于 @noescape 在 Swift 3 中已弃用(参见例如 Xcode 8 release notesSwift evolution proposal SE-0103),这意味着如果不使用已弃用的方法,就不能使非参数闭包成为非转义。
  • the following evolution thread 中所述,非参数闭包缺少@noescape 属性是一个缺失的功能(有点回归,因为这在Swift 2.2 中不是限制),但不一定是将来实施(如果我要了解 Apple 开发人员 Jordan Rose 在链接进化线程中的答案)。
  • 但是,我们可能(仍然)将已弃用的 @noescape 属性应用于非参数闭包以使其不转义,但随后会显着提示错误警告(如下所示,强调我的),现在@Hamish 已将其报告为错误,请参阅 bug report SR-2969

    @noescape是默认的,已弃用”

总而言之,localClosure 就是@escaping,自然也就不能让test(...) 的非转义闭包参数closure 进行包装。

[†] 通过非参数闭包,我指的是所有 not 函数参数的闭包,即,not 作为参数提供给函数的闭包。


作为旁注,鉴于您的问题,您可能已经知道:如果我们希望像您的示例一样处理/包装它,我们可以自然地将 closure 标记为 @escaping

func test(closure: @escaping () -> ()) -> () -> () {
    let escapingLocalClosure = { closure() }
    return escapingLocalClosure
}

【讨论】:

  • 谢谢,所以基本上如果我将一个闭包分配给一个局部变量,编译器会假定它可能比它所在的函数寿命长,从而有效地使其转义。很遗憾它无法推断它是如何使用的,因为我认为应该允许原始示例。也许在未来!
  • @dfri 为什么编译器无法检查localClosure 是否可以转义?它可以检测非转义闭包参数是否可以转义(如果它被转义闭包捕获,或者存储在比函数调用更长的变量中),如果是,则会发出错误。考虑this gist,它与标记为@noescapelocalClosure 编译得很好(尽管它会产生关于其弃用的警告)。对我来说,这只是 @noescape 弃用的一个粗略的边缘,但很可能是错误的。
  • @Hamish 根据您的论点,它确实应该能够推断出localClosure 是否可以逃脱,但目前看来(鉴于此问答)它不能。 W.r.t.要点示例:尝试使用@escaping 进行相同操作,您将收到错误消息@escaping 只能应用于函数类型的参数”@escaping 的错误和@noescape 的弃用警告提示:我会说这是某种模棱两可的 w.r.t.本地范围闭包的转义/非转义(w.r.t. 到他们的“拥有”范围)。我相信@noescape 在这个用例中也应该产生和错误。
  • ... 或所有诸如localClosure 之类的闭包默认为@escaping?甚至认为我们可能不会这样注释它们。这可以被认为是有点错误的行为吗?
  • 真正有趣的是,在 Swift 2.3 中,你甚至不能将局部变量函数标记为 @noescape,这意味着 Swift 团队同时允许在这种情况下使用 @noescape,并且已弃用它:P 我会开始写一个错误报告,看看 Swift 团队是怎么做的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-01-23
  • 2020-05-04
  • 2017-01-04
  • 1970-01-01
  • 1970-01-01
  • 2022-10-21
  • 2023-03-22
相关资源
最近更新 更多