【问题标题】:How to forward send calls from one PassthroughSubject to another (i.e. PassthroughSubject chaining)?如何将发送呼叫从一个 PassthroughSubject 转发到另一个(即 PassthroughSubject 链接)?
【发布时间】:2020-11-03 05:07:09
【问题描述】:

假设我有一个类的 API,它使用 PassthroughSubject 接收其输入:

class Logger {
  let log: PassthroughSubject<String, Never>
}

通常我可以通过调用 logger.log.send("test") 来发出一个值。

现在假设我想拥有一个位于通用记录器和我的代码之间的记录器:

class MyLogger {
  let log: PassthroughSubject<String, Never>
}

这应该作为字符串的前缀,然后将任何更新发送到 Logger。有没有办法将输出从一个 PassthroughSubject(例如 MyLogger)链接到另一个(例如 Logger)?

我知道我可以这样做:

let cancellable = myLogger.log.sink { 
  logger.log.send("[MyApp] " + $0)
}

但是,这似乎不像是将事物链接在一起的组合方式。我希望有一个我可以使用的 API 更类似于这个:

logger.log.subscribe(myLogger.log.map { "[MyApp] " + $0 })

但是,这并没有编译,因为我认为地图导致它变成了发布者而不是主题:

实例方法 'subscribe' 要求 'Publishers.Map, String>' 符合 'Subject'

除了依赖 sink 之外,是否有一种更具声明性的 API 可以让一个 PassthroughSubject 订阅来自另一个的更新(支持中间的突变)?

【问题讨论】:

    标签: swift combine


    【解决方案1】:

    如果你翻转订阅的顺序,它会起作用:

    let cancellable = myLogger.log
      .map { "[MyApp] " + $0 }
      .subscribe(logger.log)
    
    myLogger.send("test") // will send "[MyApp] test" to logger.log
    

    话虽如此,像这样使用 Combine 建模集 API 似乎有点奇怪,Failure 数据类型似乎被完全忽略了。例如。如果日志失败,则无法向链回传它失败的信息。

    一个更好的 API 可能是一个普通函数,它返回一个AnyPublisher

    class Logger {
      func log(_ string: String) -> AnyPublisher<Void, Never>
    }
    
    class MyLogger {
      func log(_ string: String) -> AnyPublisher<Void, Never> {
        return logger.log(string)
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多