如果我在闭包中使用 self,它会导致 Swift 中的内存泄漏吗?

If I use self in the closure, does it cause the memory leaks in Swift?

我是自动引用计数和内存泄漏的新手,对它们有(可能)简单的问题。 现在我大致了解了 ARC 的想法以及如何避免内存泄漏,我的问题是如果一个函数有闭包并且需要在该块中使用 self,我是否总是需要编写 [weak self] 来避免内存泄漏泄漏?

例如...

我刚刚制作了一个名为 ViewControllerA 的 class,它有一个函数 showDeleteAlert,它通过目标索引和目标 ID 删除项目。 (抱歉,这只是一个随机 class 和函数)。在 showDeleteAlert 函数的删除操作中,有一个访问 dataSource class 的删除函数的闭包。我认为我需要在闭包中使用 [weak self],因为 ViewControllerA 对 showDeleteAlert 函数有很强的引用,而 showDeleteAlert 函数在闭包中使用 self,我认为它与 ViewControllerA 有很强的联系。因此,我把 [weak self] 放在一起以避免内存泄漏。在那种情况下,我是否需要闭包中的 weak self? (如果不是,你能解释一下为什么我不需要软弱的自己吗?)

class ViewControllerA: UIViewController {
    private var dataSource = MyDataSource()
    private var targetIndex = Int()
    private var targetId = String()

    func showDeleteAlert() {
        let deleteAction = UIAlertAction(title: "DELETE", style: .destructive) { [weak self] _ in
            
            guard let strongSelf = self else {
                return
            }

            strongSelf.dataSource.delete(by: strongSelf.targetId, at: strongSelf.targetIndex, completion: strongSelf.reloadVC)
        }
        
        let cancelAction = UIAlertAction(title: Alert.ButtonTitle.cancel, style: .cancel)
        self.showAlert(title: alertTitle, message: nil, actions: [deleteAction, cancelAction], style: .actionSheet, completion: nil)
    }

    func reloadVC() {
        // do something for reload VCA
    }

}

答案取决于您未添加任何实现细节的 MyDataSourceshowAlert(title: 方法的实现,假设它没有做任何不合理的答案主要是 NO 你不需要 [weak self]

只有当循环引用导致内存中的两个对象之间出现死锁情况时才会发生内存泄漏,从而阻止它们都从内存中removed/purged。

仅仅因为你使用了一个闭包,你就不需要在闭包捕获列表中使用 [weak self] 只要你知道没有循环依赖或者换句话说循环引用。

我们分析一下:

在您的情况下,您访问 dataSourcetargetIndextargetId 并从闭包中调用实例方法 reloadVC,这意味着,除非您指定 [weak self][unowned self] 闭包将持有对 self

的强引用

显然你的 self 持有对 dataSource 和其他实例属性的强引用,假设你的 dataSource 不持有对 self 的强引用(真的无法想象一个用例,其中数据源对自身有很强的引用)依赖图无论如何都不是循环的

参考图会像

Closure -> Self -> Data Source

如果您的数据源本身持有对 Self 的强引用,那么图形将是循环的

Closure -> Self -> Data Source -> Self

或者,如果您的 Self 对您的 UIAlertController 或您的 UIAlertAction

有很强的参考意义

UIAlertController -> Closure -> self -> UIAlertController

UIAlertController -> UIAlertAction -> Closure -> self -> UIAlertAction

这就是为什么我提到答案取决于您对 showAlert(title: 方法的实施

假设你没有做任何不合理的事情(很抱歉不能想出理性推理为什么人们会强烈引用 UIAlertControllerUIAlertAction),我没有看到任何循环引用正在形成因此没有死锁,因此没有内存泄漏。

附加信息

假设存在某种循环依赖并且您想避免内存泄漏,在这种特定情况下您可能想使用 [unowned self] 而不是 [weak self]

如果您不确定 [weak self][unowned self] 之间的区别 做阅读 Shall we always use [unowned self] inside closure in Swift

希望对您有所帮助