Swift Combine 中的“空订阅者”?

"Empty Subscriber" in Swift Combine?

提问人:Gargo 提问时间:6/29/2023 更新时间:7/1/2023 访问量:87

问:

在某些情况下,应该执行代码,但不应处理其结果。

如果我使用完成块,则代码如下所示:

func someFunc(completion: (() -> ())?) { ... }

someFunc(nil)

现在,如果我使用,我应该写这样的东西:Combine

func someFunc() -> AnyPublisher<(), Never> { ... }

someFunc()
.sink { _ in
} receiveValue: {
}
.store(in: ...)

但是,它是否更方便的解决方案,例如实现协议但什么都不做的类?Subscriber

为什么需要它?例如,预加载一些不需要显示但需要缓存的远程资源。

swift combine is-empty 发布者 订阅者

评论


答:

0赞 Scott Thompson 6/30/2023 #1

“函数反应式编程 (FRP)”库(Combine 就是一个例子)接受随时间推移而到达的一系列值,通过函数转换这些值,并将最终转换结果传递给订阅者。

理想情况下,转换函数应该是纯的 - 没有副作用。

该库的根本目的是将转换后的值传递给订阅者。因此,没有内置的空订阅者。这就是你的问题的答案及其背后的原因。

换句话说,如果流水线使用纯函数,没有人关心结果,那么整个流水线就没有意义了。

你依赖于管道中确实有副作用的中间函数(不是“纯函数”)。而且你不关心最终的、转变后的价值。您的用法与FRP的一些基本原则不一致。

在我看来,我认为这是您可能有的代码味道 为作业使用了错误的工具,或者您可能没有正确使用该工具。从您的描述来看,在我看来,您的管道希望将值传递到缓存。因此,保存到缓存操作可能应该发生在 .sink

至少,我倾向于生成有关操作成功或失败的日志消息。副作用是可以预料的。sinksink

评论

0赞 Gargo 6/30/2023
sink本身应该不缓存任何东西,因为其他“工具”会这样做,记录 - 可能。我也有这样一种情况,当我需要执行一个顺序发布者时,我不确定他们的顺序将来是否会改变,所以我将它们与 和 链接起来,并使用空的flatMapcatchsink
0赞 Scott Thompson 7/1/2023
以对您有意义的方式实现应用程序。你在做什么对我来说似乎很奇怪,但我不必维护代码:-)
0赞 Daniel T. 7/1/2023 #2

直接回答您的问题:

但是,它是否更方便的解决方案,例如实现订阅者协议但什么都不做但什么都不做的类?

不,没有。在 RxSwift 中,闭包是可选的,因此您可以执行,但在 Combine 中不存在类似操作。subscribe()

为什么需要它?

您必须订阅发布者才能激活它的原因是,默认情况下它们是懒惰的。发布链是对程序的描述,而不是对所述副作用的执行。

它是命令模式的实现。创建命令对象时,不会发生任何情况。只有当你在对象上调用execute()时,才会发生一些事情。大多数出版商也是如此。创建一个除了设置上下文之外什么都不做。执行发布服务器(通过调用或其他订阅方法之一)会导致事情发生。sink

有趣的是,这是一个例外。如果你将你的副作用包裹在未来,它将在构造时立即执行它的副作用。Future

最后,副作用要么产生某些东西,要么消耗一些东西。你从服务器(生产者)获取一些东西,以便将其存储在缓存(消费者)中,这实际上是两个副作用。