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

我注意到,在 Swift 2.2中,用@noescape标记为非转义的关闭不需要显式的自我.在Swift 3中,认情况下,所有的关闭都不会转义,现在要求它们被标记为@escaping,如果你希望他们能够逃脱.

由于认情况下Swift 3中的所有关闭都是不可逃避的,为什么要求明确的自我?

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

In Swift 3,all closures are non-escaping by default

不,在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)
        }
    }
}

由于上述示例中的闭包不会转义,因此禁止其存储或捕获,从而将其使用寿命限制在函数foo(_ :)的生命周期内.因此,这意味着它捕获的任何值都保证在函数退出后不会被捕获 – 这意味着您不需要担心捕获可能发生的问题,例如保留周期.

然而,一个闭包存储属性(如上例中的bar)是通过定义进行转义的(将它们放在@noescape中是无意义的),因为它的生命周期不限于给定的函数 – 它(因此它的所有捕获的变量)只要给定的实例保留在内存中,它将保留在内存中.因此,这很容易导致诸如保留周期等问题,这就是为什么需要使用显式的自我.以使捕获语义明确.

实际上,在这个例子中,你的示例代码将在调用viewDidLoad()时创建一个保留循环,因为someClosure强烈地捕获自己,并且自己强烈地引用someClosure,因为它是一个存储的属性.

当然,一个你希望能够使用@noescape属性的地方在一个函数一个局部变量的闭包上.只要它不存储在函数外部或被捕获,这样的闭包将具有可预测的使用寿命.例如:

class A {

    let n = 5

    func foo() {

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

        f()
    }
}

不幸的是,由于@noescape在Swift 3中被删除,这是不可能的(有趣的是,在Xcode 8 GM中,这是可能的,但会产生一个弃用警告).作为Jon Shier says,我们必须等待它被重新添加到语言,这可能或可能不会发生.

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...