【问题标题】:ReactiveSwift: How to write a Task SchedulerReactiveSwift:如何编写任务调度程序
【发布时间】:2016-11-03 10:59:43
【问题描述】:

我正在尝试创建一个调度程序来消耗一些数据。

调度器必须能够:

  • 每次应手动使用数据时发送一个事件
  • 每次数据应在上次消费后的一段时间后自动消费时发送一个事件

我用MutableProperty模拟了手动消耗

 let consume = MutableProperty<Void>()

我正在尝试使用 SignalProducer 模拟自动消耗

 let timer = SignalProducer<Void, NoError>

通过结合这两个生产者的最新值,我可以第一次获得需要使用该数据的时间,例如

SignalProducer.combineLatest(consume.producer, timer)
    .take(first: 1)
    .map() { _ in return () }

这样,无论是手动消费还是自动消费,生产者都会发送一个值。

我不知道如何才能永远做到这一点。

有人可以帮忙吗?

【问题讨论】:

    标签: ios swift reactive-cocoa


    【解决方案1】:

    你可以使用ReactiveSwift中定义的全局定时器函数来启动一个定时器

    public func timer(interval: TimeInterval, on scheduler: DateSchedulerProtocol) -> SignalProducer<Date, NoError>
    

    将计时器与消耗属性结合起来:

    let interval = 10.0
    let timerSignal: SignalProducer<Date, NoError> = timer(interval: interval, on: QueueScheduler.main)
    let consume = MutableProperty<Void>()
    
    timerSignal.combineLatest(with: consume.producer).startWithValues { (date, v) in
        print("triggered at time: \(date)")
    }
    

    这样,您可以通过在使用时设置value 属性或等待计时器事件来手动触发打印块。

    【讨论】:

    • 这并不能完全回答这个问题。消费事件之间的间隔应该是 10 秒,这意味着如果在最近的消费事件之后 10 秒过去,则应该生成一个新事件。您的代码所做的(以及我提供的 sn-p)是,无论每次经过 10 秒,都会生成一个新事件。例如:假设计时器从 0 开始,手动消费事件在 4 到达。计时器将在 10 点触发,创建一个自动消费事件,但我希望它在 14 点触发(事件之间经过 10 秒)
    • 我能够通过使用每 0.5 秒触发一次的轮询生产者并将每个消费事件映射到它产生的 timeIntervarlSince1970 来近似我想做的事情。每次两者中的任何一个,计时器或消费属性,触发一个事件我简单地将当前时间间隔Since1970与最新生成的消费事件时间间隔进行比较,如果差异大于10秒,我会触发一个新的消费事件。不过,我一直在寻求更优雅的解决方案
    • 如何停止这个计时器?
    • @franck 我猜你必须得到Disposable 参考并在需要时处理它。
    【解决方案2】:

    您可以将计时器包装到 SignalProducer 中

    func timerProducer() -> SignalProducer<Void, Never> {
        return SignalProducer<Void, Never> { observer, disposable in
            let timer = Timer(timeInterval: 10, repeats: true) { timer in
                if disposable.hasEnded {
                    timer.invalidate()
                } else {
                    observer.send(value: ())
                }
            }
            RunLoop.main.add(timer, forMode: .common)
        }
    }
    

    注意:如果你从非主线程启动这个生产者,你需要将它添加到 RunLoop。否则不会触发。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-23
      • 2019-02-06
      • 2013-03-01
      • 2018-04-28
      • 2011-09-28
      • 1970-01-01
      • 2014-07-30
      相关资源
      最近更新 更多