在 Swift 中,如果我有一个捕获 [weak self] 的闭包,在闭包的开头解开可选的 self 是一种好习惯吗?

Alf*_*uro 3 closures weak-references swift

我在 macOS 应用程序中使用 Swift,Xcode 是 12.5.1。想象一下,我有以下代码:

func performAsyncTask(completion: { [weak self] (error: Error?) in 

     self?.someProperty = 0.0
     self?.someOtherProperty = 0.0
     // Other similar statements follow
})
Run Code Online (Sandbox Code Playgroud)

将其更改为:

func performAsyncTask(completion: { [weak self] (error: Error?) in 
     
     guard let self = self else { return }
     self.someProperty = 0.0
     self.someOtherProperty = 0.0
     // Other similar statements follow
})
Run Code Online (Sandbox Code Playgroud)

我相信第一个实现更好,因为 self 可能在语句之间变为 nil ,因此在开始时展开可能不那么干净。我希望专家能给我带来正确的方向。感谢您的关注。

Dun*_*n C 8

出于与您给出的相同原因,我会以另一种方式争论(在您的第一个版本中,self可以在您的闭包代码运行时随时释放)。

如果闭包在与保留 self 的代码不同的线程上运行,则在引用 的不同语句之间该对象可能会变为 nil self?。(这不太可能,但有可能。)如果您的闭包代码正在做一些比仅仅将属性分配给 self 更复杂的事情,那么self在其中进行释放可能会使整个闭包变得毫无意义,甚至使其失败。(假设您正在进行图像处理,并且图像在处理过程中消失了。)

在第二个版本中,该guard let self = self语句为闭包的范围创建了对 self 的强引用,这意味着self在闭包完成之前, by 引用的对象不会被释放。

我宁愿知道self在闭包开始时是否仍然存在,然后完全运行闭包代码,而不是必须防御性地编写我的闭包代码以不断检查“自我已被释放吗?现在怎么样?现在?好吧,现在怎么?”

就编码风格和可读性而言,必须不断处理可选的链接/绑定/零合并是一种痛苦,并且使您的代码更难遵循


mat*_*att 5

我相信第一个实现更好,因为 self 可能在语句之间变为 nil

这就是为什么第二个实现实际上更好的原因!如果self在第一个语句中不是 nil,则第一个语句使它self 不能成为nil语句之间。它self完全保留块的其余部分。这就是所谓的“弱强之舞”。

guard let self = self else { return }
      //  ^^^^ this self is _strong_, not weak; it retains self
Run Code Online (Sandbox Code Playgroud)