简体   繁体   中英

ReactiveSwift: How to write a Task Scheduler

I am trying to create a scheduler to consume some data.

The scheduler will have to be able to:

  • send an event each time data should be consumed manually
  • send an event each time data should be consumed automatically after some time has elapsed after the last consumption

I have modelled the manual consumption with a MutableProperty

 let consume = MutableProperty<Void>()

and I am trying to model the automatic consumption with a SignalProducer

 let timer = SignalProducer<Void, NoError>

I can get the first time that I need to consume that data by combining the latest values of these two producers like

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

That way whichever comes first, a manual consumption or an automatic one the producer will send a value.

I can't figure out how I will be able to do this perpetually.

Can someone help?

You can start a timer using the global timer functions defined in ReactiveSwift

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

To combine the timer with the consume property:

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)")
}

This way you can trigger the print block manually by setting the value property on consume, or by waiting for the timer event.

You can wrap timer into 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)
    }
}

Note: If you starting this producer from NON-main thread, you need add it to RunLoop. Otherwise it will not get triggered.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM