Учитывая список таймеров, как вывести его, если один из них завершен, и в то же время иметь возможность сброса списка? - PullRequest
0 голосов
/ 05 ноября 2018

У меня есть выходной сигнал, который должен выводиться, когда один из заданных таймеров истекает, завершается или когда весь список сбрасывается.

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 ]

0 голосов
/ 05 ноября 2018

Это похоже на работу для шаблона слияния / перечисления. Я сам, скорее, 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.
}
0 голосов
/ 05 ноября 2018

Здесь немного сложно увидеть полный вариант использования, поэтому я просто опишу, как я могу различить стрельбу 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 и определить, будет ли добавлено новое действие или выполнен сброс.

...