Last active
June 29, 2023 13:06
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// 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 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)") | |
} | |
} | |
} |
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
why is this not good for production?