如何将呼叫从一个PassthroughSubject转发到另一个(即PassthroughSubject链接)?

时间:2020-07-13 22:43:48

标签: swift combine

想象一下,我有一个使用PassthroughSubject来接收其输入的类的API:

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 })

但是,由于我认为地图导致地图变成了发布者而不是主题,因此无法编译:

实例方法“订阅”要求“ Publishers.Map ,字符串>”符合“主题”

除了依赖sink之外,是否还有一种更具说明性的API,可以使一个PassthroughSubject订阅另一个PassthroughSubject的更新(支持它们之间的突变)?

1 个答案:

答案 0 :(得分:0)

如果您翻转订阅的顺序,它将起作用:

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

myLogger.send("test") // will send "[MyApp] test" to logger.log

话虽这么说,用Combine对这样的set 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)
  }
}