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

为什么在Swift 3中默认情况下不关闭转义的闭包为什么需要显式的“ self”?

公西姚石
2023-03-14
问题内容

我注意到在Swift 2.2中,标为non-escaped的闭包@noescape不需要explicit self。在Swift
3中,默认情况下,所有闭包都是不转义的,@escaping如果您希望它们能够转义,现在要求将其标记出来。

鉴于默认情况下Swift 3中的所有闭包都是非转义的,为什么它们需要显式的self

final class SomeViewController: NSViewController {

    var someClosure: () -> () = { _ in }

    override func viewDidLoad() {
        super.viewDidLoad()

        someClosure = {
            view.layer = CALayer() // ERROR: Implicit use of `self` in closure; use `self.` to make capture semantics explicit
        }
    }
}

问题答案:

在Swift 3中,默认情况下所有闭包都不转义

不,在Swift 3中,默认情况下仅闭包 函数参数
(即,函数本身就是函数输入)不转义(根据SE-0103)。例如:

class A {

    let n = 5
    var bar : () -> Void = {}

    func foo(_ closure: () -> Void) {
        bar = closure // As closure is non-escaping, it is illegal to store it.
    }

    func baz() {
        foo {
            // no explict 'self.' required in order to capture n,
            // as foo's closure argument is non-escaping,
            // therefore n is guaranteed to only be captured for the lifetime of foo(_:)
            print(n)
        }
    }
}

由于closure在上面的示例中是不可转义的,因此禁止将其存储或捕获,因此将其生存期限制为该函数的生存期foo(_:)。因此,这意味着保证它捕获的任何值在函数退出后都不会保留—这意味着您不必担心捕获可能会发生的问题,例如保留周期。

然而,一个闭合件 存储的属性 (例如,bar在上面的例子)是由定义逸出(这将是无意义的与将其标记@noescape)作为它的寿命
限定于给定功能的-它(以及因此它的所有捕获的变量)将保持在只要给定实例保留在内存中即可。因此,这很容易导致诸如保留周期之类的问题,这就是为什么您需要使用一个显式self.的以便使捕获语义显式的原因。

实际上,html" target="_blank">举例来说,您的示例代码在viewDidLoad()被调用时会创建一个保留周期,因为它是一个存储属性,因此someClosure强烈地捕获selfself强烈引用someClosure了它。

值得注意的是,作为“存储的函数属性始终转义”规则的扩展,聚合中存储的函数(即具有关联值的结构和枚举)也总是转义,因为对此类聚合没有任何限制。正如pandaren
codemaster指出的那样, 当前 包括Optional–意味着Optional<() -> Void>(aka。(() -> Void)?)总是在逃避。鉴于可选参数已经建立在许多编译器魔术上,因此编译器最终可能会将其作为函数参数的特殊情况。

当然,您希望能够使用该@noescape属性的一个地方是闭包,该闭包是函数中的局部变量。只要不将其存储在函数外部或未被捕获,此类闭合将具有可预测的寿命。例如:

class A {

    let n = 5

    func foo() {

        let f : @noescape () -> Void = {
            print(n)
        }

        f()
    }
}

不幸的@noescape是,这在Swift 3中已被删除,这是不可能的(有趣的是,在Xcode 8
GM中,这是可能的,但是会产生弃用警告)。正如JonShier所说,我们必须等待它重新添加到语言中,这可能会或可能不会发生。



 类似资料:
  • 问题内容: 谁能向我解释为什么Hibernate 默认情况下不设置注释,而是允许实体根据当前设置的属性生成INSERT? 什么是不使用的原因,因此默认情况下包括所有实体属性? 问题答案: @ jb-nizet说了什么。 另外,在我的书中是个坏主意。 从生成的SQL跳过空字段,很快您将发现自己处于声明列的情况,这实际上导致持久数据与休眠知道的实体数据不同。这会造成挫败感,并可能使您诉诸昂贵的电话。

  • 我是个新手,我已经开始学习了。但我有些问题。为什么我们需要使用Mockito?据我所知,它用于模拟(创建虚拟对象),并在实际运行代码之前编写测试用例。但是,如果我想测试我已经实现的代码,以检查它们是否正常工作,该怎么办。我怎么用mockito来测试它呢? 例如,我有CRUD方法,我想通过实际使用我的Create方法在数据库中插入数据来测试Create是否正常工作,其他人也是如此。我们能用莫基托来实

  • 我在java selenium上编写了一个try/catch块,我不明白为什么它不能工作。它应该在网页上检查一个web元素,如果没有找到,它应该抛出一个NoSuchElementException并转到catch块。真正发生的情况是,没有找到元素,执行也没有继续catch块,它通过测试(Selenium WebTest)并完全停止执行,我的测试也失败了。我还在main方法中包含了“throws N

  • 本文向大家介绍什么是闭包(closure)为什么要用它相关面试题,主要包含被问及什么是闭包(closure)为什么要用它时的应答技巧和注意事项,需要的朋友参考一下 闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域,将函数内部的变量和方法传递到外部。 闭包的特性: 1.函数内再嵌套函数

  • 问题内容: 通常,当我打开文件时,我从不调用该方法,也不会发生任何不良情况。但是有人告诉我这是不好的做法。这是为什么? 问题答案: 在大多数情况下,不关闭文件是一个坏主意,原因如下: 它会将您的程序放在垃圾收集器的手中-尽管 理论上 该文件将自动关闭,但可能不会关闭。Python 3和Cpython通常在垃圾收集方面做得相当不错,但并非总是如此,其他变体通常也很烂。 它可能会降低您的程序速度。打开

  • TCP可以检测数据包是否成功发送,所以与其等待pong命令,为什么不在ping命令发送时检查是否有错误呢?我只是不觉得需要乒乓球。