Учитывая список таймеров, как вывести его, если один из них завершен, и в то же время иметь возможность сброса списка?
У меня есть выходной сигнал, который должен выводиться, когда один из заданного таймера истекает, завершается или когда весь список сбрасывается.
enum DeviceActionStatus {
case pending
case completed
case failed
}
struct DeviceAction {
let start: Date
let status: DeviceActionStatus
func isTimedOut() -> Bool // if start is over 30 seconds ago
let id: String
}
Выходной сигнал:
let pendingActionUpdated: Signal<[DeviceAction], NoError>
Входы:
let completeAction: Signal<String, NoError>
let tick: Signal<Void, NoError> // runs every 1 second and should iterate to see if any DeviceAction is timed out
let addAction: Signal<DeviceAction, NoError>
let resetAllActions: Signal<Void, NoError>
Он должен вывести массив всех запущенных действий устройства.
let output = Signal.combineLatest(
addAction,
resetAllActions,
tick,
Signal.merge(
completeAction,
tick.take(first: 1).map { _ in "InvalidActionId" }
)) // make sure the combinelatest can fire initially
Я пытался отправить это в.scan для кумуляции каждый раз, когда addAction
срабатывает и сбрасывается каждый раз, когда resetAllActions
уволен, но так как нет способа узнать, кто из этих уволен, я не могу заставить логику работать. Как я могу как накапливать растущий список, так и иметь возможность просматривать его и сбрасывать, когда захочу?
2 ответа
Это похоже на работу для шаблона слияния / перечисления. Я сам больше RxSwift, но если вы отобразите каждый из ваших сигналов в перечисление и объедините их, то вы сможете получить их должным образом в своем сканировании...
enum ActionEvent {
case complete(String)
case tick
case add(DeviceAction)
case reset
}
merge(
completeAction.map { ActionEvent.complete($0) },
tick.map { ActionEvent.tick },
addAction.map { ActionEvent.add($0) },
resetAllActions.map { ActionEvent.reset }
).scan([DeviceAction]()) { actions, event in
switch event {
case let .complete(id):
return actions.filter { $0.id != id }
case .tick:
return actions.filter { $0.isTimedOut() == false }
case let .add(action):
return actions + [action]
case .reset:
let resetDate = Date()
return actions.map { $0.start = resetDate }
// or
return []
// depending on what "reset" means.
}
Немного сложно увидеть полный вариант использования здесь, поэтому я просто опишу, как я бы различал addAction
а также resultAllActions
быть уволенным, оставляя остальную часть дизайна в покое.
Вы можете объединить эти два в один сигнал до Signal.combineLatest
, Для этого вам необходимо сопоставить их с одним и тем же типом. Перечисление идеально подходит для этого:
enum Action {
case add(DeviceAction)
case resetAll
}
Теперь вы можете отобразить каждый сигнал и объединить их в один сигнал:
let action = Signal.merge(
addAction.map { Action.add($0) },
resetAllActions.map { _ in Action.resetAll })
Теперь вы можете включить значение в вашем scan
и определить, будет ли добавлено новое действие или выполнен сброс.