作者:真实的嘻嘻哈哈 | 来源:互联网 | 2024-10-30 11:55
在Swift3中,默认情况下不自动关闭转义闭包的原因是为了避免潜在的内存管理和生命周期问题。明确使用“self”则是为了提高代码的可读性和安全性,确保开发者清楚地意识到闭包捕获了外部变量,从而避免意外的引用循环和资源泄漏。
在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.
的以便使捕获语义显式的原因。
实际上,举例来说,您的示例代码在viewDidLoad()
被调用时会创建一个保留周期,因为它是一个存储属性,因此someclosure
强烈地捕获self
并self
强烈引用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所说,我们必须等待它重新添加到语言中,这可能会或可能不会发生。