Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 给定一个计时器列表,如果其中一个计时器已完成,如何输出,同时还能重置该列表?_Swift_Reactive_Reactive Swift - Fatal编程技术网

Swift 给定一个计时器列表,如果其中一个计时器已完成,如何输出,同时还能重置该列表?

Swift 给定一个计时器列表,如果其中一个计时器已完成,如何输出,同时还能重置该列表?,swift,reactive,reactive-swift,Swift,Reactive,Reactive Swift,我有一个输出信号,当一组给定的计时器中的一个超时、完成或整个列表重置时,应该输出该信号 enum DeviceActionStatus { case pending case completed case failed } struct DeviceAction { let start: Date let status: DeviceActionStatus func isTimedOut() -> Bool // if start i

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

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>

我已尝试将此发送到.scan,以便在每次触发
addAction
时累积,并在每次触发
resetAllActions
时重置,但由于无法知道触发了哪些操作,因此我无法使逻辑工作。我如何既能累积一个不断增长的列表,又能运行它,并能在需要时重置它?

这里很难看到完整的用例,因此我将仅描述如何区分
addAction
resultAllActions
被激发,而不考虑设计的其余部分

您可以在
信号之前将这两个信号合并为一个信号。CombineTest
。为此,您需要将它们映射到同一类型。枚举非常适合于此:

enum Action {
    case add(DeviceAction)
    case resetAll
}
现在,您可以映射每个信号并将其合并为单个信号:

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

现在,您可以打开
扫描中的值,并确定它是正在添加的新操作还是重置。

这看起来像是合并/枚举模式的作业。我自己更喜欢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.
}

你能把
isTimedOut
变成一个信号吗?
completeAction
是否包含刚刚完成的DeviceAction的ID?@DanielT。我不认为这是一个问题,不,但是每秒钟查看一次挂起的列表,看是否有计时器超时,这是一个问题吗?考虑到这么多的行动,这似乎更有效。如果添加了任何操作,我也应该得到一个“自由”运行,因为我可以在其中进行迭代,而不是使用这种模式,但看起来非常有希望!我将对此进行测试,从未想过以这种方式实际操作。对于其他一些想法:使用scan而不是CombineTest的有趣方式,我将进行验证,谢谢!是的,当您试图维护状态时,这是反应式编程中经常使用的模式。
scan
保存状态,枚举案例基本上类似于以某种方式修改状态的方法。
let action = Signal.merge(
    addAction.map { Action.add($0) },
    resetAllActions.map { _ in Action.resetAll })
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.
}