2016-01-22 62 views
0
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 

在我看来,这是因为“人”是可选的,因此斯威夫特保持在“你好”关闭弱引用,是这样吗?

+0

可选项没有微弱存储。如果这是你想要的,你需要声明'人'为'弱'。但是弱对象*必须是可选项。 – MaddTheSane

+0

这不是原来的问题,请不要改变它,直到你得到所有的答案。 – Cristik

回答

1

因为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 
+0

将变量声明为可选不会影响它的保留方式。你持有一个对'Optional'枚举的引用,该枚举继而持有对盒装值的引用,所以你仍然得到一个保留。 – Cristik

+0

这不是我说的。我指出的是,在示例代码中,html变量在某个时间点的refcount为2,但Person()永远不会获得超过1的refcount(在我的示例中,同样的事情)。 –

+0

明白了,谢谢,我误解了你答案中的第一句话。 – Cristik

1

你不会得到保留循环,因为hello闭合捕捉一个变量,而不是一个常数,是因为变量是有望在将来改变,它不保留它,它只是持有对它的引用。

将其转换为一个常数,你会获得预期的保留周期:

func test() { 
    let html = Person() 
    html.hello = {() -> Void in 
     print("\(html.name)") 
    } 
} 
test() 

这仅打印init Person,虽然功能结束时,html超出范围,应被释放。

如果将变量定义为__block,则该行为与Objective-C等效。