不同的闭合为保留周期提供了不同的结果 [英] Different closures giving different results for retain cycles in swift
问题描述
我正在阅读Apple的《 Swift编程语言指南》.在有关闭合的强引用循环的部分中,我尝试了另一种类型的闭合,但未给出预期的输出.
I am reading Apple's Swift Programming Language Guide. In the part about Strong Reference Cycle for closures, I tried a different type of closure but it did not give the expected output.
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
即使没有[unown self],也会打印"p正在被初始化"
"p is being deinitialised" is printed even without [unowned self]
指南中的代码为:
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
仅当添加[unown self]语句时,此命令才会显示取消初始化消息.
This prints the deinitialiser message only when the [unowned self] statement is added.
两个闭包之间有什么区别?
What is the difference between both the closures?
推荐答案
好问题!为了对其进行探索,我们应该将测试用例简化为证明它所需的最小数量:
Great question! To explore it, we should simplify the test case to the minimum required to demonstrate it:
// 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
.请注意,这里有一个简短的保留循环,但是没关系.最终它被打破了,这就是一切.
In the first case, there is no permanent retain loop. When you access lazyName
, a closure is evaluated { return self.name }
. That closure captures self
, computes a string, and returns the string. The string is assigned to the property. We're now done with the closure, so it's released, and it releases self
. Note that there is a brief retain loop here, but that's ok. It is eventually broken, and that's all that matters.
在第二种情况下,存在一个永久的保留循环.当您访问lazyFunc()
时,它将调用一个闭包,该闭包将创建一个新闭包.该新的闭包是{return self.name}
,并且已分配给该属性.而且该闭包保留self
,因此永不中断的保留循环也是如此.将[unowned self] in
添加到lazyFunc
中,将为您打破循环.
In the second case, there is a permanent retain loop. When you access lazyFunc()
, it calls a closure that creates a new closure. That new closure is {return self.name}
, and that is assigned to the property. And that closure retains self
, so is a retain loop that is never broken. Adding [unowned self] in
to lazyFunc
as marked would break the loop for you.
这篇关于不同的闭合为保留周期提供了不同的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!