由于默认情况下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,我们必须等待它被重新添加到语言,这可能或可能不会发生.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。