为什么这不会导致Swift中的保留周期?

时间:2016-01-22 01:20:24

标签: 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

控制台输出是:

init Person
deinit Person

在我看来,因为'person'是一个可选的,所以Swift在'hello'闭包中保持弱引用,是吗?

2 个答案:

答案 0 :(得分:2)

你没有得到一个保留周期,因为hello闭包正在捕获一个变量,而不是一个常量,并且由于变量预计将来会改变,所以它不会保留它,它只是保持对它的引用。

将其转换为常量,您将获得预期的保留周期:

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

这仅打印init Person,但是当函数结束时,html超出范围并应该被释放。

如果您将变量定义为Objective-C,则行为与__block行为相同。

答案 1 :(得分: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