为什么这不会导致Swift中的保留周期?
问题描述:
class Person {
var hello : (() -> Void)?
var name = "name"
init() {
print("init \(self)")
}
deinit {
print("deinit \(self)")
}
}
var person : Person!
person = Person()
person.hello = {() -> Void in
print("\(person.name)")
}
person = nil
和控制台输出为:为什么这不会导致Swift中的保留周期?
init Person
deinit Person
在我看来,这是因为“人”是可选的,因此斯威夫特保持在“你好”关闭弱引用,是这样吗?
答
因为html是一个可选项,所以你的闭包实际上持有对enum(可选)的引用,而不是对象本身,所以只有一个对Person()的引用。
如果您创建了一个html实际上超出了范围的情况,那么对Person()对象的引用会一直存在,因为捕获将是对html变量唯一的剩余引用。 但它仍然不是具有引用计数的Person()对象。
class Person {
var hello : (() -> Void)?
var name = "name"
init() {
print("init \(self)")
}
deinit {
print("deinit \(self)")
}
}
repeat
{
var html : Person
html = Person()
// this closure keep a reference to 'html'
html.hello = {() -> Void in
print("\(html.name)")
}
} while false
答
你不会得到保留循环,因为hello
闭合捕捉一个变量,而不是一个常数,是因为变量是有望在将来改变,它不保留它,它只是持有对它的引用。
将其转换为一个常数,你会获得预期的保留周期:
func test() {
let html = Person()
html.hello = {() -> Void in
print("\(html.name)")
}
}
test()
这仅打印init Person
,虽然功能结束时,html
超出范围,应被释放。
如果将变量定义为__block
,则该行为与Objective-C
等效。
可选项没有微弱存储。如果这是你想要的,你需要声明'人'为'弱'。但是弱对象*必须是可选项。 – MaddTheSane
这不是原来的问题,请不要改变它,直到你得到所有的答案。 – Cristik