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

Reset SignalProducer state based on timer and result

我有一个 SignalProducer producer 异步发送 Ints。我可以用

对值求和
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.

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

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