Reputation: 103
I'm working on updating an app from Swift 3 to Swift 5. This requires updating ReactiveCocoa. There is some code that was using a timer within a SignalProducer
that no longer works when updating. Here is the before and after:
func start(beats: [Beat]) -> SignalProducer<PlayedBeat, Error> {
var index: Int = 0
let oneSecondTimer = timer(interval: DispatchTimeInterval.seconds(1), on: QueueScheduler(), leeway: DispatchTimeInterval.milliseconds(100))
.on(starting: {
// initialize
index = -1
}, value: { date in
index += 1
})
.flatMap(.latest) { [weak self] (_: Date) -> SignalProducer<PlayedBeat, Error> in
guard let strongSelf = self else {
return SignalProducer<PlayedBeat, Error>(error: Error.unknown("self reference missing"))
}
if index < beats.count {
let data = beats[index].toDeviceFormat()
strongSelf.device.writeRate(data: data, delegate: strongSelf)
return SignalProducer<PlayedBeat, Error>(value: "boom")
} else {
return SignalProducer<PlayedBeat, Error>(error: Error.noMoreData).delay(1.0, on: QueueScheduler.main)
}
}
let startSignal = SignalProducer<PlayedBeat, Error> { [weak self] (innerSink, disposable) in
guard let strongSelf = self else {
innerSink.send(error: Error.unknown("self reference missing"))
return
}
strongSelf.beatSink = innerSink
let beatDisposable = oneSecondTimer.observe(innerSink, during: strongSelf.reactive.lifetime)
disposable += {
let data = DatedBeat.stopPlayingDeviceFormat()
strongSelf.device.writeRate(data: data, delegate: strongSelf)
}
disposable.add(beatDisposable)
}
return startSignal
.on(
started: { _ in
print("Start sending beats")
},
failed: { (error) in
print("error \(error)")
},
completed: { _ in
print("completed stopped beating ")
})
}
func start(beats: [DatedBeat]) -> SignalProducer<PlayedBeat, Error> {
var index: Int = 0
let oneSecondTimer = SignalProducer.timer(interval: DispatchTimeInterval.seconds(1), on: QueueScheduler.main, leeway: DispatchTimeInterval.milliseconds(100))
.on(starting: {
// initialize
index = -1
}, value: { date in
index += 1
})
.flatMap(.latest) { [weak self] (_: Date) -> SignalProducer<PlayedBeat, Error> in
guard let strongSelf = self else {
return SignalProducer<PlayedBeat, Error>(error: Error.unknown("self reference missing"))
}
if index < beats.count {
let data = beats[index].toDeviceFormat()
strongSelf.device.writeRate(data: data, delegate: strongSelf)
return SignalProducer<PlayedBeat, Error>(value: "boom")
} else {
return SignalProducer<PlayedBeat, Error>(error: Error.noMoreData)
.delay(1.0, on: QueueScheduler.main)
}
}
let startSignal = SignalProducer<PlayedBeat, Error> { [weak self] (innerSink, lifetime) in
guard let strongSelf = self else {
innerSink.send(error: Error.unknown("self reference missing"))
return
}
strongSelf.beatSink = innerSink
if lifetime.hasEnded {
let data = DatedBeat.stopPlayingDeviceFormat()
strongSelf.device.writeRate(data: data, delegate: strongSelf)
innerSink.sendInterrupted()
return
}
_ = oneSecondTimer.observe(on: innerSink as! Scheduler)
}
return startSignal.on(
started: {
print("Start sending beats")
},
failed: { (error) in
print("error \(error)")
},
completed: {
print("completed stopped beating ")
})
}
Currently the line _ = oneSecondTimer.observe(on: innerSink as! Scheduler)
throws an error when trying to case innerSink
to Scheduler
. If I remove that line, then the timer is never started.
If anyone has thoughts on the proper way to start a timer in ReactiveCocoa, that would be super helpful. Thanks!
Upvotes: 1
Views: 362