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.
}