我应该在计算属性的闭包中使用弱自我吗?

nRe*_*wik 5 closures retain-cycle swift

我对self在闭包内使用感到困惑。

我们应该什么时候申报[weak self]?我理解的一个明显案例是

class Foo{

    var closure: ( Void -> Void )?
    var x = 0

    func doSomething(){
        closure = { [weak self] in
            if let x = self?.x{
                println(x)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我想创建一个计算属性bar,它有一个闭包,并在内部捕获 self 。像这样,

extension Foo{

    var bar: Bar{
        let bar = Bar()
        bar.completionHandler = {
            println(self.x)
        }
        return bar
    }
}
Run Code Online (Sandbox Code Playgroud)

我应该[weak self]在这个闭包内使用吗?

Rob*_*Rob 3

考虑:

\n\n
extension Foo {\n    var bar: Bar {\n        let bar = Bar()\n        bar.completionHandler = {\n            print(self.x)\n        }\n        return bar\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

我应该[weak self]在这个闭包内使用吗?

\n
\n\n

通常当人们问这个问题时,真正关心的是 \xe2\x80\x9cdo 我需要[weak self]避免强引用循环吗?\xe2\x80\x9d 答案是,不,这里没有强引用循环。

\n\n

如果bar是存储的财产,则缺少[weak self]会引发危险信号。Foo如果我们有一个存储对 a 的引用的 a Bar,而它本身有一个self包含对原始 的引用的闭包,那么很容易出现问题Foo。但有了这个计算属性,Foo\xe2\x80\x99t 没有任何强引用bar,因此强引用循环问题大大减少。

\n\n

话虽如此,我很难想象我不想使用[weak self]. 如果barcompletionHandler,则意味着它\xe2\x80\x99s可能在某些异步场景中使用,问题是是否Foo在这个过程中是否需要保留。

\n\n

因此,您使用的 \xe2\x80\x9cshould\xe2\x80\x9d 的真正问题[weak self]归结为它是什么Bar,以及它是否对 拥有任何合理的所有权主张Foo

\n\n

让\xe2\x80\x99s尝试举一个实际的例子。(以下内容有点做作,因为我很难想象这种模式的良好用例,但请耐心等待。)

\n\n

例如,让\xe2\x80\x99s 假设它Foo是一个Person对象并且BarURLSessionTask图像下载任务的一些对象:

\n\n
class Person {\n    let name: String\n    private(set) var image: UIImage?\n\n    ...\n}\n\nextension Person {\n    var imageTask: URLSessionTask {\n        let url = ...\n        return session.dataTask(with: url) { [weak self] data, _, _ in\n            guard let data = data, let image = UIImage(data: data) else { return }\n\n            self?.image = image\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以控制器可能会说

\n\n
let person = Person(...)\nlet task = person.imageTask\ntask.resume()\n
Run Code Online (Sandbox Code Playgroud)\n\n

在上面的例子中,我碰巧使用了[weak self]imageTask包,并不是因为我担心任何强引用循环,而只是因为网络任务通常没有必要对模型对象声明强引用。(然后,我也不会\xe2\x80\x99个人将网络接口埋入模型对象中。)但是在这个例子中,[weak self]如果你想确保该Person对象是保留直到网络请求完成(例如,您可能想将网络请求的结果保存在某些本地持久存储中)。

\n\n

话虽如此,我真的很难想象我会使用上述模式。但最重要的是,这里没有强引用循环,所以理论上你可以忽略 而[weak self]不用担心。但在大多数实际场景中,您通常最终会使用[weak self].

\n