Strong reference cycles with closures使用闭包的强引用循环

15 浏览
0 Comments

Strong reference cycles with closures使用闭包的强引用循环

我正在尝试了解什么时候需要密切关注由强引用循环引起的可能的内存泄漏。从我从Swift文档中了解到的情况来看,如果在同一实例中声明为实例属性的闭包中使用self引用,将会导致强引用循环,除非我声明一个捕获列表,如:

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

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

admin 更改状态以发布 2023年5月23日
0
0 Comments

你所询问的情况不会导致引用循环。

只有当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捕获对象是一个不错的做法,除非你有充分的理由不这样做。

0