Skip to content

Instantly share code, notes, and snippets.

@stevestreza
Last active June 29, 2023 13:06
Show Gist options
  • Save stevestreza/9eccb7f88f2e0e4e97835dd00f706036 to your computer and use it in GitHub Desktop.
Save stevestreza/9eccb7f88f2e0e4e97835dd00f706036 to your computer and use it in GitHub Desktop.
A basic implementation of a Scheduler for Combine. Probably not a great implementation. Useful only as a toy, do not ship this.
//
// DispatchQueueScheduler.swift
//
import Combine
import Foundation
// DO NOT USE THIS IN PRODUCTION
struct DispatchQueueScheduler: Scheduler {
let queue: DispatchQueue
init(dispatchQueue: DispatchQueue) {
self.queue = dispatchQueue
}
func schedule(after date: DispatchTime, interval: Int64, tolerance: Int64, options: DispatchQueue?, _ action: @escaping () -> Void) -> Cancellable {
var cancelled = false
let queue = self.queue
let timer = DispatchSource.makeTimerSource(flags: DispatchSource.TimerFlags(), queue: queue)
timer.schedule(deadline: date, repeating: DispatchTimeInterval.nanoseconds(Int(interval)), leeway: DispatchTimeInterval.nanoseconds(Int(tolerance)))
timer.setEventHandler {
queue.async {
if !cancelled {
action()
}
}
}
timer.resume()
return AnyCancellable {
timer.cancel()
cancelled = false
}
}
func schedule(after date: DispatchTime, tolerance: Int64, options: DispatchQueue?, _ action: @escaping () -> Void) {
queue.asyncAfter(deadline: date, execute: action)
}
func schedule(options: DispatchQueue?, _ action: @escaping () -> Void) {
queue.async(execute: action)
}
typealias SchedulerTimeType = DispatchTime
typealias SchedulerOptions = DispatchQueue
var now: DispatchTime {
return DispatchTime.now()
}
var minimumTolerance: Int64 {
return Int64(1)
}
}
// Some junk to make all the protocols work
extension Int64: SchedulerTimeIntervalConvertible {
public static func seconds(_ s: Int) -> Int64 {
return Int64(s * 1000000000)
}
public static func seconds(_ s: Double) -> Int64 {
return Int64(s * 1000000000)
}
public static func milliseconds(_ ms: Int) -> Int64 {
return Int64(ms * 1000000)
}
public static func microseconds(_ us: Int) -> Int64 {
return Int64(us * 1000)
}
public static func nanoseconds(_ ns: Int) -> Int64 {
return Int64(ns)
}
}
extension DispatchTime: Strideable {
public func distance(to other: DispatchTime) -> Int64 {
return Int64(rawValue) - Int64(other.rawValue)
}
public func advanced(by n: Int64) -> DispatchTime {
return DispatchTime(uptimeNanoseconds: UInt64(Int64(rawValue) + n))
}
public typealias Stride = Int64
}
struct Example {
static func run() {
let scheduler = DispatchQueueScheduler(dispatchQueue: DispatchQueue.main)
print("Start: \(Date())")
let _ = (0..<10).publisher()
.delay(for: DispatchTime.Stride.seconds(2), scheduler: scheduler)
.sink { (value) in
print("\(Date()) Value \(value)")
}
}
}
@aswathr
Copy link

aswathr commented May 11, 2022

why is this not good for production?

@stevestreza
Copy link
Author

You can use DispatchQueue directly as a Scheduler. I didn't know that when I wrote this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment