Как переадресовать отправленные вызовы от одного PassthroughSubject к другому (например, цепочка PassthroughSubject)?

Представьте, что у меня есть 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 ‹PassthroughSubject‹ String, Never ›, String›' соответствовал 'Subject'.

Есть ли более декларативный API для того, чтобы заставить один объект PassthroughSubject подписываться на обновления от другого (с поддержкой промежуточных мутаций), помимо использования sink?


person Senseful    schedule 13.07.2020    source источник


Ответы (1)


Если вы перевернете порядок подписки, это сработает:

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

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

Сказав это, API-интерфейсы моделирования, подобные этому, с Combine кажутся немного странными, а тип данных 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)
  }
}
person Senseful    schedule 14.07.2020