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

前端之家收集整理的这篇文章主要介绍了为什么在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,我们必须等待它被重新添加到语言,这可能或可能不会发生.

猜你在找的Swift相关文章