提问人:Gargo 提问时间:6/29/2023 更新时间:7/1/2023 访问量:87
Swift Combine 中的“空订阅者”?
"Empty Subscriber" in Swift Combine?
问:
在某些情况下,应该执行代码,但不应处理其结果。
如果我使用完成块,则代码如下所示:
func someFunc(completion: (() -> ())?) { ... }
someFunc(nil)
现在,如果我使用,我应该写这样的东西:Combine
func someFunc() -> AnyPublisher<(), Never> { ... }
someFunc()
.sink { _ in
} receiveValue: {
}
.store(in: ...)
但是,它是否更方便的解决方案,例如实现协议但什么都不做的类?Subscriber
为什么需要它?例如,预加载一些不需要显示但需要缓存的远程资源。
答:
“函数反应式编程 (FRP)”库(Combine 就是一个例子)接受随时间推移而到达的一系列值,通过函数转换这些值,并将最终转换结果传递给订阅者。
理想情况下,转换函数应该是纯的 - 没有副作用。
该库的根本目的是将转换后的值传递给订阅者。因此,没有内置的空订阅者。这就是你的问题的答案及其背后的原因。
换句话说,如果流水线使用纯函数,没有人关心结果,那么整个流水线就没有意义了。
你依赖于管道中确实有副作用的中间函数(不是“纯函数”)。而且你不关心最终的、转变后的价值。您的用法与FRP的一些基本原则不一致。
在我看来,我认为这是您可能有的代码味道
为作业使用了错误的工具,或者您可能没有正确使用该工具。从您的描述来看,在我看来,您的管道希望将值传递到缓存。因此,保存到缓存操作可能应该发生在 .sink
至少,我倾向于生成有关操作成功或失败的日志消息。副作用是可以预料的。sink
sink
评论
sink
本身应该不缓存任何东西,因为其他“工具”会这样做,记录 - 可能。我也有这样一种情况,当我需要执行一个顺序发布者时,我不确定他们的顺序将来是否会改变,所以我将它们与 和 链接起来,并使用空的flatMap
catch
sink
直接回答您的问题:
但是,它是否更方便的解决方案,例如实现订阅者协议但什么都不做但什么都不做的类?
不,没有。在 RxSwift 中,闭包是可选的,因此您可以执行,但在 Combine 中不存在类似操作。subscribe()
为什么需要它?
您必须订阅发布者才能激活它的原因是,默认情况下它们是懒惰的。发布链是对程序的描述,而不是对所述副作用的执行。
它是命令模式的实现。创建命令对象时,不会发生任何情况。只有当你在对象上调用execute()时,才会发生一些事情。大多数出版商也是如此。创建一个除了设置上下文之外什么都不做。执行发布服务器(通过调用或其他订阅方法之一)会导致事情发生。sink
有趣的是,这是一个例外。如果你将你的副作用包裹在未来,它将在构造时立即执行它的副作用。Future
最后,副作用要么产生某些东西,要么消耗一些东西。你从服务器(生产者)获取一些东西,以便将其存储在缓存(消费者)中,这实际上是两个副作用。
评论