swift - 为什么 Swift 闭包不捕获 self ?

标签 swift closures automatic-ref-counting

我正在使用 Xcode Playground 测试快速关闭。

这是我的代码:

import UIKit

class A{
    var closure: ()->() = {}

    var name: String = "A"
    init() {
        self.closure = {
            self.name = self.name + " Plus"
        }
    }

    deinit {
        print(name + " is deinit")
    }
}

var a: A?
a = A()
a = nil

正如预期的那样,a 由闭包自包含,因此 a 永远不会被释放。

但是,当我在最后一行之前添加这一行时:

a?.closure = { a?.name = "ttt" }

然后,我在输出窗口中发现“A is deinit”,这意味着a被释放了。 为什么?是不是回收引用?

为了测试,我使用一个函数来设置闭包,代码是版本2:

import UIKit

class A{
    var closure: ()->() = {}
    func funcToSetClosure(){
        self.closure = { self.name = "BBB"}
    }
    var name: String = "A"
    init() {
        self.closure = {
            self.name = self.name + " Plus"
        }
    }

    deinit {
        print(name + " is deinit")
    }
}



var a: A?


a = A()


a?.funcToSetClosure()


a = nil

同样,a 永远不会被释放。

所以我得出的结论是,闭包在init或者类中的函数中设置时,会引起循环引用,在类外设置时,不会引起循环引用。我说得对吗?

最佳答案

两种情况下都有循环保留。不同之处在于引用 的性质,而不是设置闭包地方。这种差异体现在如何打破这个循环:

  • 在“内部”情况下,闭包内部的引用是self。当您释放对 a 的引用时,不足以 打破循环,因为循环是直接自引用的。要打破循环,您还可以a.closure 设置为 nil,然后再将 a 设置为 nil,而你没有这样做。

enter image description here

  • 在“外部”情况下,引用是a。只要您的 a 引用未设置为 nil,就会有一个保留周期。但您最终确实将其设置为nil,这足以打破循环。

enter image description here

(插图来自Xcode的内存图功能。太酷了。)

关于swift - 为什么 Swift 闭包不捕获 self ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40978533/

相关文章:

arrays - 如何使用属性观察器观察具有 Swift 集合类型的特定元素?

swift - 第二个 TableView 不显示任何/正确的嵌套数组值

javascript - 使用 Object.DefineProperty 并访问私有(private)范围内的变量

JavaScript 闭包(this)

c++ - C++ 辅助类的潜在 ARC 保留周期?

ios - 啊!不允许 ARC 错误 :'CFTypeRef' (又名 'const void *' )到 'NSNumber *'

ios - 在用户无法访问的地方快速保存图片

iOS - 尺寸类别的不同堆栈 View

Swift - 返回此函数

ios - 在 Swift 中如何知道该结构已从内存中删除?