I am trying to create a date scheduler to observe some event. But it does not work. I've looked through
protocol DateScheduler
and it is said that action will take place at currentDate in some methods protocol DateScheduler. I am trying doing this after 10 sec. Below is an example of my custom schedular.
class SomeDateScheduler : DateScheduler {
var currentDate: Date
init() {
self.currentDate = Date(timeIntervalSinceNow: 10)
}
func schedule(after date: Date, action: @escaping () -> Void) -> Disposable? {
print(#function)
print(date)
return nil
}
func schedule(after date: Date, interval: DispatchTimeInterval, leeway: DispatchTimeInterval, action: @escaping () -> Void) -> Disposable? {
print(#function)
print(date)
print(interval)
print(leeway)
return nil
}
func schedule(_ action: @escaping () -> Void) -> Disposable? {
print(#function)
return nil
}
}
and then I create bind to observe event
private func testSchedular() {
let schedular = SomeDateScheduler()
reactive.makeBindingTarget { appDeleg, value in
print("SUCCESS")
print(value)
} <~ signalSchedular.observe(on: schedular)
DispatchQueue.main.async { [observerSchedular] in
observerSchedular.send(value: "Hello World")
observerSchedular.sendCompleted()
}
}
I am doing it into AppDelegate. ObserverSchedular and signalSchedular are global properties. Please, explain to me how to invoke all methods DateScheduler.
I have already understood where I made mistake. To fix it I done next:
observe(on: Schedular)
. So it looked like this (add these function in extension to Signal
):func customObserve(on scheduler: DateScheduler, interval: Int, leeway: Int) -> Signal<Value, Error> {
return customFlatMapEvent(Signal.Event.observe(on: scheduler, interval: DispatchTimeInterval.seconds(interval), leeway: DispatchTimeInterval.seconds(leeway)))
}
func customFlatMapEvent<U, E>(_ transform: @escaping Event.CustomTransformation<U, E>) -> Signal<U, E> {
return Signal<U, E> { output, lifetime in
let input = transform(output.send, lifetime)
lifetime += self.observe(input)
}
}
also add this
extension Signal.Event {
typealias CustomTransformation<U, E: Swift.Error> = (@escaping Signal<U, E>.Observer.Action, Lifetime) -> Signal<Value, Error>.Observer.Action
static func observe(on scheduler: DateScheduler, interval: DispatchTimeInterval, leeway: DispatchTimeInterval) -> CustomTransformation<Value, Error> {
return { action, lifetime in
lifetime.observeEnded {
scheduler.schedule {
action(.interrupted)
}
}
return { event in
scheduler.schedule(after: scheduler.currentDate, interval: interval, leeway: leeway) {
if !lifetime.hasEnded {
action(event)
}
}
}
}
}
}
Created bind for observation in didFinishLaunchingWithOptions
reactive.makeBindingTarget { appDeleg, value in
print("SUCCESS")
print(value)
} <~ signalSchedular.customObserve(on: schedular, interval: 10, leeway: 1)
And simulate async code
DispatchQueue.main.async { [observerSchedular] in
observerSchedular.send(value: "Hello World")
observerSchedular.sendCompleted()
}
private let (signalSchedular, observerSchedular) = Signal<String, Never>.pipe(),
let schedular = SomeDateScheduler()
class SomeDateScheduler : DateScheduler {
var currentDate: Date
init() {
self.currentDate = Date()
}
func schedule(after date: Date, action: @escaping () -> Void) -> Disposable? {
action()
return nil
}
func schedule(after date: Date, interval: DispatchTimeInterval, leeway: DispatchTimeInterval, action: @escaping () -> Void) -> Disposable? {
if case .seconds(let sec) = interval {
let time = DispatchTime.now() + DispatchTimeInterval.seconds(sec)
let queue = DispatchQueue(label: "sads", qos: .utility, attributes: .concurrent)
queue.asyncAfter(deadline: time) { [weak self] in
_ = self?.schedule(after: date) {
action()
}
}
DispatchQueue.main.asyncAfter(deadline: time) { [weak self] in
_ = self?.schedule(after: date) {
action()
}
}
}
return nil
}
func schedule(_ action: @escaping () -> Void) -> Disposable? {
action()
return nil
}
}