【发布时间】:2019-07-19 18:41:55
【问题描述】:
我在 Xcode Playground 中用以下代码进行了实验:
class X {
var a = 3
init(a: Int) {
self.a = a
}
deinit {
print("\(self.a) is deallocated.")
}
func returnX() -> Int {
return self.a
}
lazy var anotherReturnX: () -> Int = {
return self.a
}
}
var e: X? = X(a: 6)
print(e!.returnX())
e = nil // prints "6 is deallocated."
var f: X? = X(a: 7)
print(f!.anotherReturnX())
f = nil // prints nothing
从上面的代码中,我可以看到函数returnX() 中没有捕获任何引用,因此一旦我将e 设置为nil,e 就会被释放。但是,在闭包anotherReturnX() 中捕获了一个引用,因此f 不会被释放。显然,这意味着闭包会捕获引用,而函数不会。
另外,当我第一次输入代码时,我没有在闭包声明之前包含 lazy 关键字,因为我认为没有必要这样做。但是它会触发编译时错误。我推断由于闭包只能在实例化后访问,它必须访问实例化的self。但是既然我在这里声明的实际上是一个“匿名函数”,为什么在实例化期间闭包访问self?
经过一番思考,我发现了更多的矛盾。例如,我知道在调用闭包时会捕获引用。然而,在X 的初始化过程中,我只是分配一个闭包给一个变量而不调用它,与其他实例属性的声明相同。因此闭包在初始化期间不应该做任何事情,并且编译没有关键字lazy的代码应该没问题。但是编译失败。我不确定我的理解出了什么问题。
我已经阅读了一些相关的文章,例如强/弱引用、保留周期、惰性存储属性。然而,许多人解释“发生了什么”,并没有过多地谈论“为什么”。
所以除了标题中提出的问题之外,我还想澄清一下,是什么让函数和闭包彼此不同,从而导致上述情况发生?
更新:
闭包捕获引用而函数没有捕获引用这一事实在我身上进一步“强制”,因为根据 Xcode 编译器,我可以在 returnX() 中将 return self.a 重写为 return a,但我不能这样做anotherReturnX。因此,我想我不得不接受这一点,虽然函数和闭包是相似的,因为它们都是“一组功能”,但函数 与闭包不同,它不捕获引用。如果再深究这背后的原因,大概会涉及到 Swift 本身的设计吧?
但是,我还是不明白为什么闭包声明需要lazy关键字。
【问题讨论】:
-
请转至stackoverflow.com/a/38141553/5519329。它可能对您的问题有所帮助。
标签: swift function closures lazy-evaluation conceptual