3

我有一个输出信号,当给定的一组定时器超时、完成或整个列表被重置时,它应该输出。

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,但由于无法知道其中的触发,我无法使逻辑正常工作。我怎样才能既累积一个不断增长的列表,同时又能够运行它并能够在我想要的时候重置它?

4

2 回答 2

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.
}
于 2018-11-05T14:29:32.973 回答
1

在这里看到完整的用例有点困难,所以我将只描述我将如何区分addActionresultAllActions被解雇,剩下的设计就不用说了。

您可以在Signal.combineLatest. 为此,您需要将它们映射到相同的类型。枚举非常适合:

enum Action {
    case add(DeviceAction)
    case resetAll
}

现在您可以映射每个信号并将它们合并为一个信号:

let action = Signal.merge(
    addAction.map { Action.add($0) },
    resetAllActions.map { _ in Action.resetAll })

现在您可以打开您的值scan并确定它是添加的新操作还是重置。

于 2018-11-05T14:27:30.553 回答