带有闭包的强引用循环



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

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

现在,不存储为实例属性的闭包或存储为其他类的实例属性的closures会发生什么?在这些情况下,我还需要担心强参考周期吗?

您询问的案例不会导致引用周期

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

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捕获对象是一种很好的做法,除非您有充分的理由不这样做。

相关内容

  • 没有找到相关文章

最新更新