关于Swift中闭包的强引用循环问题

3
我定义了一个名为Person的类。这是我的代码:
    class Person { 
        var closure: (() -> ())?
        var name: String

        init(name: String) {

            self.name = name
            print("\(name) is being initialized")
        }

        deinit {
            print("\(name) is being deinitialized")
        }
    }

然后我在名为ViewController的类中使用Person

class ViewController: UIViewController {

    var person = Person(name: "john")
    let aStr = "john is a cute boy"


    override func viewDidLoad() {
        super.viewDidLoad()

        person.closure = {
            print("\(self.aStr)")
        }
        person.closure!()
    }
}

在我看来,关于我的代码的记忆就像这样:memory

因此,从上面的图片可以看出,在我看来,这将在三个实例之间引起强引用循环,但我无法从Instruments中获取任何泄漏信息,所以我有些困惑。

这段代码是否会引起强引用循环?

如果不是,那么ARC什么时候会释放Person类的实例?Person类中名为deinit的方法从未被调用。


正如@Puttin所述,这确实有一个保留环,但这并不是泄漏。当一个对象具有非零保留计数,但是没有引用时,就会出现泄漏。在这里,您具有非零保留计数,但仍然存在引用。它们是循环引用,但这并不会导致泄漏。 - Paulw11
哦,我明白了,非常感谢。但是现在我有另一个问题,如果它不会导致内存泄漏,我需要解决它吗?还是它会在其他地方引起泄漏? - XM Zhang
它会导致内存“丢失”,因为它将阻止这些对象被释放,所以是的,你应该使用弱引用来避免它。这只是一个泄漏工具无法为你找到的问题。 - Paulw11
1个回答

2

是的,这是一个典型的保留周期问题。

为了解决这个问题,在闭包中使用[weak self]

person.closure = { [weak self] in
    guard let strongSelf = self else { return }
    print("\(strongSelf.aStr)")
}

如何真正创建一个泄漏。

我创建了一个演示应用,根是一个navController。

navController有一个根控制器,我们称之为buttonController。

当你在buttonController中点击按钮时,它会创建你的ViewController并将其推到navController中。

当你在导航栏中点击返回按钮时,navController弹出你的ViewController实例。

使用Instruments对其进行分析,你会看到泄漏和保留周期。

Xcode iOS应用程序的默认模板使用单个页面,该页面始终保留您的ViewController实例。如果系统仍在使用ViewController实例,则实际上还没有泄漏。因此,推送和弹出为您显示了泄漏。


@Paulw11 真的吗?需要那个 '`' 符号吗? - Puttin
2
使用一个新的名称,比如strongSelf,怎么样? - vacawama
@vacawama 是的,那样很酷。我过去常常这样写。已更新。 - Puttin
1
为什么我的instrumentsleaks没有泄漏? - XM Zhang
@XiaoMZhang,获取泄漏的简单方法就像我所做的那样。多次推入和弹出ViewController。 - Puttin
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接