我应该在 PromiseKit 块中使用 [weak self] 吗?

Should I use [weak self] in PromiseKit blocks?

PromiseKit 在 their website 上声明如下:

Should I be concerned about retain cycles?

tl;dr: it’s safe to use self in promise handlers.

This is safe:

somePromise.then {
    self.doSomething()
}

Provided somePromise resolves, the function passed to then will be released, thus specifying [weak self] is not necessary.

Specifying [unowned self] is likely dangerous.

You’re telling me not to worry about retain cycles?!

No, it’s just that by default you are not going to cause retain cycles when using PromiseKit. But it is still possible...

这是否意味着我不应该在 PromiseKit 块中使用 [weak self]?有没有我仍然需要使用 [weak self] 的情况?它究竟是如何防止保留周期的?

TL;DR:继续在 PromiseKit 块中使用 [weak self] 以防止对象的寿命超过必要的时间。


有几点需要注意。首先,在块中使用 [weak self] 有两个主要原因:

  1. 防止保留循环
  2. 防止对象活得比必要的时间长

其次,PromiseKit 在您调用该代码块时创建一个保留周期。 self 通常坚持 somePromise,而 somePromise 通常坚持 self。他们说你 不应该关心 这个保留周期的原因是因为保留周期将被 PromiseKit 自动打破。当then被释放时,somePromise将不再持有self,从而打破保留循环。

所以我们知道我们不需要担心 PromiseKit 块的问题 #1,但是问题 #2 呢?

想象一下,一个视图控制器触发了一个网络请求承诺,并且需要 30 秒才能解决这个承诺。现在在解决之前,用户按下后退按钮。通常 UIKit 会释放视图控制器,因为它不再在屏幕上并且系统可以节省资源。但是,由于您在 promise 中引用了 self ,因此无法再对其进行释放。这意味着视图控制器在内存中的寿命将比必要时间长 30 秒。

解决问题 #2 的唯一方法是在块中使用 [weak self]

注意:有人可能会争辩说,当您的视图控制器退出时,无论如何您都应该取消正在进行的承诺,以便它释放对 self 的保留。但是,确定何时应释放视图控制器是 not a simple task。让 UIKit 为您处理逻辑要容易得多,如果您确实需要在释放视图控制器时执行任何操作,请在视图控制器的 dealloc 方法中实现它。如果块强烈保留在视图控制器上,这将不起作用。


更新:看起来像 one of the authors did talk about this 并阐明了提出这些建议的原因:

In fact, retaining self is probably what you want so to allow the promise to resolve before self is deallocated.

该文档只是说您不必担心 PromiseKit 引入 "strong reference cycles"(以前称为 "retain cycles"),因为当 promise 实现并且块完成时 运行,那些强引用会自动为你解析。强引用与弱引用的选择完全取决于您。

例如,如果您只是更新场景中不再存在的 UI 个元素,则无需保留对已关闭视图控制器的强引用。在这种情况下,您会使用 weak。但有时您需要强引用(例如,您可能希望更新底层模型以反映承诺的成功或失败)。

最重要的是,他们所说的只是您不应该让 PromiseKit 决定强引用与弱引用,而应该由您的应用程序更广泛的设计要求来驱动。关于 PromiseKit 的唯一硬性规则是你应该避免 unowned.