swift - 为什么添加闭包捕获列表会阻止我的实例被释放?

标签 swift closures reference-cycle

class Name {
    var name: String
    init(name: String) {
        self.name = name
    }
    deinit {
        print("\(name) deinit")
    }
}
var x: Name? = Name(name: "abc")

var someClosure = {
    print("\(x?.name)")
}

someClosure()

x = nil

然后控制台会输出:

Optional("abc")
abc deinit

可以看出调用了“deinit”函数。所以没有形成强引用循环。 但是如果我在闭包中添加一个捕获列表:

var someClosure = { [x] in
    print("\(x?.name)")
}

控制台会输出:

Optional("abc")

并且没有调用“deinit”函数。所以对象和引用形成了一个强引用循环。

这是什么原因?这两个条件有什么区别?

最佳答案

首先,在这两种情况下都没有强保留循环——你只是有一个全局闭包变量,它持有对你的类实例的强引用,因此防止它被释放。 p>

在您的第一个示例中,当您在闭包中捕获 x 时:

var someClosure = {
    print("\(x?.name)")
}

你得到的(实际上)是对引用的引用——也就是说,闭包有一个对 x 存储的引用,然后它有一个对你的类实例的引用。当您将 x 设置为 nil 时 – 闭包仍然引用 x 的存储,但现在是 x 没有对您的类实例的引用。因此,您的类实例不再对它有任何强引用,并且可以被释放。

在您使用 capture list 的第二个示例中:

var someClosure = { [x] in
    print("\(x?.name)")
}

您正在复制 x 本身——也就是说,您正在复制对您的类实例的引用。因此,只要它存在,闭包就会保留你的类。将 x 设置为 nil 不会影响闭包对您实例的引用,因为它拥有对它的强引用。

关于swift - 为什么添加闭包捕获列表会阻止我的实例被释放?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43421961/

相关文章:

ios - 快速比较 NSDates

ios - 从内存中释放 SKTextureAtlas

javascript - 需要解释 : Cannot understand javascript returning a function

javascript - 相同的 JS 闭环问题 - 但 SO 的答案不起作用

ios - 强,弱或无主引用周期与定时器

java - 是否可以从其终结器跟踪对象,以检测其他对象的终结器对对象的意外复活?

ios - UISearchBarDelegate 函数 -searchBarSearchButtonClicked 不工作

ios - 隐藏导航栏分隔线并保持状态栏与导航栏颜色相同

Javascript:如何将变量的值(而不是引用)传递给函数?