【问题标题】:Strong reference cycles with closures带闭包的强参考循环
【发布时间】:2015-05-06 00:09:57
【问题描述】:

我试图了解何时需要注意由强引用循环引起的可能的内存泄漏。根据我从 swift 文档中收集到的信息,在声明为同一实例中的实例属性的闭包中使用 self 引用将导致强引用循环,除非我声明一个捕获列表,例如:

class A {

    var a: String

    lazy var aClosure: () -> () = { [unowned self] in
        println(self.a)
    }

    init(a: String) {
        self.a = a
    }
}

现在,未存储为实例属性的闭包或存储为其他类的实例属性的闭包会发生什么情况?在这些情况下,我还需要担心强引用循环吗?

【问题讨论】:

    标签: ios swift memory-leaks closures strong-references


    【解决方案1】:

    您询问的案例不会导致引用循环

    仅当 2 个或更多对象直接或间接具有指针(或由属性内的块捕获)彼此时才会发生引用循环:

    A->B and B->A (direct)
    A->B, B->C, C->A (indirect)
    

    现在不存储为实例属性的闭包会发生什么

    通常你可能会看到一个视图控制器调用一些库并提供处理程序块。 例如:

    // inside some method of view controller
    APIWrapper.sharedInstance().callApiWithHandler(handler: { 
         (finished: Bool) -> Void in
        // process result of the action
        self.showResults()
    }
    

    在这种情况下,您不知道需要多长时间才能完成此操作。 您的区块可能会被提交到私有操作队列中。在此操作完成之前,所有捕获的对象都将保持活动状态。

    即使是危险的部分:如果用户按下后退按钮(假设涉及导航控制器)并且当前视图控制器从导航堆栈中弹出,它将保持活动状态,因为捕获了self,即使它不会显示在屏幕上。

    这应该改写为:

        // inside some method of view controller
        APIWrapper.sharedInstance().callApiWithHandler(handler: { 
             [weak self]
             (finished: Bool) -> Void in
            // process result of the action
            self?.showResults()
        }
    

    作为其他类的实例属性存储的闭包

    这部分类似:您可能无法控制保持对块的引用的对象的生命周期。

    被捕获的对象是隐式引用,可能难以调试。

    总而言之:使用区块时,您应该始终考虑该区块的生命周期以及它是否会产生循环。使用weak/unowned 捕获对象是一种很好的做法,除非您有充分的理由不这样做。

    【讨论】:

    • aClosure 在语法上不正确。我在上面改变了它——现在,根据apple's documentation,这会导致一个强大的参考周期,对吧?
    • 你是对的:没有lazy 的第一个版本是不正确的。不:您的示例不会产生参考周期,因为您使用 unowned 关键字捕获 selfweakunowned 之间的区别在于 weak 会将类型更改为可选,而 unowned 不会。但是它们都产生了一个弱参考。请查看此答案stackoverflow.com/a/26025176,了解weakunowned 之间的区别
    • 不,这就是我最初的意思,但后来在评论中颠倒了它——由于捕获列表,它不会声明一个强引用循环,但它不会。很抱歉造成混乱,感谢您对此的看法!
    • "即使不会显示在屏幕上,它也会因为捕获的自我而保持活动状态。"这不一定是问题
    猜你喜欢
    • 2020-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 1970-01-01
    • 2014-02-01
    • 1970-01-01
    相关资源
    最近更新 更多