【问题标题】:Should I use [weak self] in PromiseKit blocks?我应该在 PromiseKit 块中使用 [weak self] 吗?
【发布时间】:2017-01-09 21:49:59
【问题描述】:
PromiseKit 在their website 上声明如下:
我应该关注保留周期吗?
tl;dr:在 promise 处理程序中使用 self 是安全的。
这是安全的:
somePromise.then {
self.doSomething()
}
如果somePromise解析,传递给then的函数将被释放,因此不需要指定[weak self]。
指定 [unowned self] 可能很危险。
你是在告诉我不要担心保留周期?!
不,只是默认情况下,在使用 PromiseKit 时不会导致保留循环。不过还是可以的……
这是否意味着我永远不应该在 PromiseKit 块中使用[weak self]?有没有我仍然需要使用[weak self] 的情况?它究竟是如何防止保留循环的?
【问题讨论】:
标签:
swift
retain-cycle
promisekit
【解决方案1】:
TL;DR:继续在 PromiseKit 块中使用 [weak self] 以防止对象的寿命超过必要的时间。
有几点需要注意。首先,在一个块中使用[weak self] 有两个主要原因:
- 防止保留循环
- 防止对象的寿命过长
其次,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 并澄清了提出这些建议的原因:
事实上,保留self 可能是您想要的,以便在释放self 之前解决promise。
【解决方案2】:
该文档只是说您不必担心 PromiseKit 引入“强引用周期”(以前称为“保留周期”),因为当承诺实现并且块完成运行时,这些强引用会自动为你解决。强引用和弱引用的选择完全取决于您。
例如,如果您只是更新场景中不再存在的 UI 元素,则无需保留对已关闭视图控制器的强引用。在那种情况下你会使用weak。但有时您需要强引用(例如,您可能希望更新底层模型以反映 Promise 的成功或失败)。
归根结底,他们只是说您不应该让 PromiseKit 决定强引用和弱引用,而应该由应用程序更广泛的设计要求驱动。 PromiseKit 唯一的硬性规则是你应该避免unowned。