在定义或首次调用时,闭包是否分配了内存?例如,名称asHTML
的闭包是在实例化HTMLElement
headerTitle
时实例化的,或者在调用asHTML()
时的下一行。此外,对于类,提供了deinit实现。闭包是否有类似的功能?
class HTMLElement {
let name: String
let text: String?
lazy var asHTML: () -> String = {
return "<\(self.name)>\(self.text ?? "")</\(self.name)>"
}
init(name: String, text: String? = nil) {
self.name = name
self.text = text
}
deinit {print("\(name) is being deinitialized")}
}
var headerTitle: HTMLElement? = HTMLElement(name: "h1", text: "Welcome")
print(headerTitle!.asHTML())
headerTitle = nil
答案 0 :(得分:1)
通常,需要在其定义站点分配闭包,以便捕获闭包内使用的闭包之外的变量。但是,lazy
关键字使得闭包在第一次使用之前不会被声明。来自Apple的documentation
惰性存储属性是一个属性,其初始值在第一次使用之前不会计算。通过在声明之前编写惰性修饰符来指示延迟存储的属性。
我假设你的意思是 deinit for closure意味着在你的闭包中释放对引用语义变量的任何强引用。您的示例来自Apple自己的 Swift编程指南(Swift 4)。他们解释说这个例子有一个强大的引用循环,这意味着类实例拥有对闭包的强引用,而闭包具有对该实例的强引用。并且nether愿意互相释放,导致实例永远不会被初始化。这是Apple的视觉效果:
如果您仔细阅读本章的内容,他们会谈到定义捕获列表以打破强大的参考周期。
lazy var asHTML: () -> String = {
[unowned self] in /*<-- Add self in the capture list, so the closure does not have a strong reference to the instance. */
if let text = self.text {
return "<\(self.name)>\(text)</\(self.name)>"
} else {
return "<\(self.name) />"
}
}
现在,当headerTitle
设置为nil
时,将显示deinit
打印消息。