我正在阅读 Apple 的 Swift 编程语言指南。在关于闭包的强引用循环的部分中,我尝试了一种不同类型的闭包,但它没有给出预期的输出。
class HTMLElement {
let name: String
let text: String?
lazy var asHTML : String = {
//[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}()
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
println("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
println(paragraph!.asHTML)
paragraph = nil
该代码的输出是:
<p>hello, world</p>
p is being deinitialized
即使没有 [unowned self] 也会打印“p is being deinitialized”
指南中的代码是:
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
[unowned self] in
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {
println("\(name) is being deinitialized")
}
}
var paragraph: HTMLElement? = HTMLElement(name: "p", text: "hello, world")
println(paragraph!.asHTML)
paragraph = nil
仅当添加 [unowned self] 语句时,才会打印 deinitialiser 消息。
这两种闭包有什么区别?
好问题!为了探索它,我们应该将测试用例简化到演示它所需的最低限度:
// First case, a lazy string
class LazyVar {
let name = "LazyVar"
lazy var lazyName : String = { return self.name }()
deinit {
println("\(name) is being deinitialized")
}
}
var lazyVar: LazyVar? = LazyVar()
println(lazyVar?.lazyName)
lazyVar = nil // Calls deinit
// Second case, a lazy ()->String
class LazyFunc {
let name = "LazyFunc"
lazy var lazyFunc: () -> String = {
// [unowned self] in // <-- This would break the loop
return self.name
}
deinit {
println("\(name) is being deinitialized")
}
}
var lazyFunc: LazyFunc? = LazyFunc()
println(lazyFunc?.lazyFunc())
lazyFunc = nil // Doesn't call deinit
在第一种情况下,没有永久的保留循环。当您访问lazyName
,评估闭包{ return self.name }
。该闭包捕获了self
,计算一个字符串,并返回该字符串。该字符串被分配给属性。我们现在已经完成了关闭,所以它被释放了,它也被释放了self
。请注意,这里有一个简短的保留循环,但没关系。它最终会被打破,这才是最重要的。
在第二种情况下,存在永久保留循环。当您访问lazyFunc()
,它调用一个闭包来创建一个新的关闭。新的关闭是{return self.name}
,并将其分配给该属性。并且该关闭保留了self
,永不中断的保留循环也是如此。添加[unowned self] in
to lazyFunc
如标记所示,将为您打破循环。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)