根据计时器和结果重置SignalProducer状态

时间:2018-04-24 05:45:02

标签: frp reactive-swift

我有SignalProducer producer异步发送Int s。我可以用

加总值
producer.scan(0, +)

假设我想将总和重置为0,如果它是> 10并且没有其他值发送1秒。我的第一次尝试看起来像这样:

producer
  .scan(0, +)
  .flatMap(.latest) { n -> SignalProducer<Int, NoError> in
    if n <= 10 {
        return SignalProducer(value: n)
    } else {
        return SignalProducer.merge([
            SignalProducer(value: n),
            SignalProducer(value: 0).delay(1, on: QueueScheduler.main)
            ])
    }
  }

虽然这正确发送了0,但它并未重置scan中的状态。也就是说,9, 8, long pause, 7的序列发送9, 17, 0, 24

有没有办法以正确重置状态的方式组合这两个概念?

1 个答案:

答案 0 :(得分:1)

我会使用startWithSignal来获取对生成的Signal的访问权限,以便创建重置触发器以与传入值合并。我使用枚举作为我的值,以指示进入scan的值是重置触发器还是累积Int

enum ValOrReset {
    case val(Int)
    case reset
}


producer.startWithSignal { signal, _ in
    resetTrigger = signal
        .debounce(TimeInterval(1.0), on: QueueScheduler.main)
        .map { _ in .reset }

    signal
        .map { val in .val(val) }
        .merge(with: resetTrigger)
        .scan(0) { (state, next) in
            switch next {
            case .val(let val):
                return state + val
            case .reset:
                if state > 10 {
                    return 0
                }
                else {
                    return state
                }
            }
        }
        .observeValues { val in
            print(val)
        }
}

startWithSignal的工作方式是确保在闭包完成之前不会出现任何值,这意味着您可以创建多个下游信号并将它们连接在一起而不必担心丢失任何值,即使生产者发送值同步。