Swift:使用弱自我在基于块的执行中保持原子性



我经常看到使用弱自我的代码,如下所示:

api.call() { [weak self] (result, error) in
if (error == nil) {
setGlobalState()
self?.doSomething()
} else {
setSomeErrorState()
self?.doSomethingElse()
}
}

但在我看来,如果 self 为零,现在状态不一致,因为 setGlobalState(( 会执行但 self?。doSomething(( 没有。

明智的做法似乎是:

api.call() { [weak self] (result, error) in
guard let self = self else { return }
if (error == nil) {
setGlobalState()
self.doSomething()
} else {
setSomeErrorState()
self.doSomethingElse()
}
}

我对第一种情况下缺乏原子性的担忧是否合理?当涉及到使用弱自我的块时,后一种情况应该是最佳实践吗?

这个问题没有简单的答案,因为正确答案取决于doSomethingdoSomethingElse在做什么,这里不清楚。

话虽如此,你说:

我经常看到使用弱自我的代码,如下所示:

api.call() { [weak self] (result, error) in
if error == nil {
setGlobalState()
self?.doSomething()
} else {
setSomeErrorState()
self?.doSomethingElse()
}
}

但在我看来,如果自我为零,现在状态是不一致的,因为setGlobalState()会执行,但self?.doSomething()没有。

从技术上讲,这确实可能是一个问题,但这是一个非常不寻常的情况。但如果这是一个问题,那可能是更深层次问题的代码气味。

通常,当您看到类似这样的内容时,doSomethingdoSomethingElse正在更新 UI 或任何self所特有的内容,其中上述模式实际上是可取的。上面的代码片段可确保发生setGlobalStatesetSomeErrorState,但如果self是视图控制器,则可确保我们不会人为地保留它,只是为了更新不再存在的 UI。

但是,如果doSomethingdoSomethingElse不仅仅是更新 UI,而是像您在随后的评论中建议的那样"设置一些单例状态",那么您是对的,上述内容不会实现您想要的。

所以,你继续说:

明智的做法似乎是:

api.call() { [weak self] (result, error) in
guard let self = self else { return }
if error == nil {
setGlobalState()
self.doSomething()
} else {
setSomeErrorState()
self.doSomethingElse()
}
}

这里的挑战是,如果在调用 API 完成处理程序之前解除分配self,那么它不会执行任何操作。您已执行 API 调用,但不会调用setGlobalState/doSomethingsetSomeErrorState/doSomethingElse。因此,如果您确实在设置全局状态和单例属性,那么您是对的,它们将在内部保持一致,但它们现在可能与您的 Web 服务不同步。

仅当 (a( 必须使用第二种模式,例如,如果调用setGlobalState,则还必须调用doSomething;但是 (b( 如果self解除分配,则这些方法都不被调用是可以的。

您可能需要考虑第三种选择,即完全省略[weak self]

api.call() { result, error in
if error == nil {
setGlobalState()
self.doSomething()
} else {
setSomeErrorState()
self.doSomethingElse()
}
}

如果必须在 API 调用完成后同时调用setGlobalStatedoSomething(或setSomeErrorStatedoSomethingElse(,那么我们根本不会使用[weak self]。(请注意,这仅在正确实现api时才有效,设计为在完成时不会挂在闭包上,但无论如何,所有设计良好的异步 API 都会这样做。

但是,应该注意的是,如果setGlobalStatedoSomething之间(或setSomeErrorStatedoSomethingElse之间(之间确实存在一些隐藏的全局依赖关系,这表明设计中存在更深层次的问题。单独的对象应松散耦合。使用全局或有状态单例是值得怀疑的,更不用说让应用程序开发人员承担保持两者同步的责任了。

最重要的是,这三种api完成替代方案的选择完全取决于self是什么,doSomething做什么,doSomethingElse做什么。我不会断然拒绝第一种选择,因为它通常是正确的解决方案。

相关内容

  • 没有找到相关文章

最新更新