闭包是在定义或首次调用时分配内存吗?

时间:2018-01-25 02:03:02

标签: swift memory-management closures

在定义或首次调用时,闭包是否分配了内存?例如,名称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

1 个答案:

答案 0 :(得分:1)

通常,需要在其定义站点分配闭包,以便捕获闭包内使用的闭包之外的变量。但是,lazy关键字使得闭包在第一次使用之前不会被声明。来自Apple的documentation

  

惰性存储属性是一个属性,其初始值在第一次使用之前不会计算。通过在声明之前编写惰性修饰符来指示延迟存储的属性。

我假设你的意思是 deinit for closure意味着在你的闭包中释放对引用语义变量的任何强引用。您的示例来自Apple自己的 Swift编程指南(Swift 4)。他们解释说这个例子有一个强大的引用循环,这意味着类实例拥有对闭包的强引用,而闭包具有对该实例的强引用。并且nether愿意互相释放,导致实例永远不会被初始化。这是Apple的视觉效果: enter image description here

如果您仔细阅读本章的内容,他们会谈到定义捕获列表以打破强大的参考周期。

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) />"
    }
}

enter image description here

现在,当headerTitle设置为nil时,将显示deinit打印消息。