Files
UUVPN/iOS-SwiftUI-Code/GRDB.swift-6.29.3/GRDB/ValueObservation/ValueObservationScheduler.swift
T

126 lines
3.9 KiB
Swift

import Dispatch
import Foundation
/// A type that determines when `ValueObservation` notifies its fresh values.
///
/// ## Topics
///
/// ### Built-In Schedulers
///
/// - ``async(onQueue:)``
/// - ``immediate``
/// - ``AsyncValueObservationScheduler``
/// - ``ImmediateValueObservationScheduler``
public protocol ValueObservationScheduler {
/// Returns whether the initial value should be immediately notified.
///
/// If the result is true, then this method was called on the main thread.
func immediateInitialValue() -> Bool
func schedule(_ action: @escaping () -> Void)
}
extension ValueObservationScheduler {
func scheduleInitial(_ action: @escaping () -> Void) {
if immediateInitialValue() {
action()
} else {
schedule(action)
}
}
}
// MARK: - AsyncValueObservationScheduler
/// A scheduler that asynchronously notifies fresh value of a `DispatchQueue`.
public struct AsyncValueObservationScheduler: ValueObservationScheduler {
var queue: DispatchQueue
public init(queue: DispatchQueue) {
self.queue = queue
}
public func immediateInitialValue() -> Bool { false }
public func schedule(_ action: @escaping () -> Void) {
queue.async(execute: action)
}
}
extension ValueObservationScheduler where Self == AsyncValueObservationScheduler {
/// A scheduler that asynchronously notifies fresh value of the
/// given `DispatchQueue`.
///
/// For example:
///
/// ```swift
/// let observation = ValueObservation.tracking { db in
/// try Player.fetchAll(db)
/// }
///
/// let cancellable = try observation.start(
/// in: dbQueue,
/// scheduling: .async(onQueue: .main),
/// onError: { error in ... },
/// onChange: { (players: [Player]) in
/// print("fresh players: \(players)")
/// })
/// ```
///
/// - warning: Make sure you provide a serial queue, because a
/// concurrent one such as `DispachQueue.global(qos: .default)` would
/// mess with the ordering of fresh value notifications.
public static func async(onQueue queue: DispatchQueue) -> AsyncValueObservationScheduler {
AsyncValueObservationScheduler(queue: queue)
}
}
// MARK: - ImmediateValueObservationScheduler
/// A scheduler that notifies all values on the main `DispatchQueue`. The
/// first value is immediately notified when the `ValueObservation`
/// is started.
public struct ImmediateValueObservationScheduler: ValueObservationScheduler, Sendable {
public init() { }
public func immediateInitialValue() -> Bool {
GRDBPrecondition(
Thread.isMainThread,
"ValueObservation must be started from the main thread.")
return true
}
public func schedule(_ action: @escaping () -> Void) {
DispatchQueue.main.async(execute: action)
}
}
extension ValueObservationScheduler where Self == ImmediateValueObservationScheduler {
/// A scheduler that notifies all values on the main `DispatchQueue`. The
/// first value is immediately notified when the `ValueObservation`
/// is started.
///
/// For example:
///
/// ```swift
/// let observation = ValueObservation.tracking { db in
/// try Player.fetchAll(db)
/// }
///
/// let cancellable = try observation.start(
/// in: dbQueue,
/// scheduling: .immediate,
/// onError: { error in ... },
/// onChange: { (players: [Player]) in
/// print("fresh players: \(players)")
/// })
/// // <- here "fresh players" is already printed.
/// ```
///
/// - important: this scheduler requires that the observation is started
/// from the main queue. A fatal error is raised otherwise.
public static var immediate: ImmediateValueObservationScheduler {
ImmediateValueObservationScheduler()
}
}