mirror of
https://github.com/samsonjs/AsyncMonitor.git
synced 2026-06-29 05:19:29 +00:00
Drop iOS 17 / macOS 14 support
This commit is contained in:
parent
c2a231a40f
commit
6ec19f4c25
8 changed files with 14 additions and 159 deletions
|
|
@ -2,7 +2,12 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
- Your change here.
|
||||
### Removed
|
||||
- **Breaking**: Dropped support for iOS 17 and macOS 14. Minimum platforms are now iOS 18.0 and macOS 15.0.
|
||||
- Removed the iOS 17 compatibility variants of `AsyncMonitor.init`, `AsyncSequence.monitor`, and `NSObjectProtocol.monitorValues` along with their `@Sendable` closure requirements.
|
||||
|
||||
### Changed
|
||||
- The remaining `monitor` and `monitorValues` APIs no longer carry `@available` gates and rely on the actor-isolation-aware overloads that previously required iOS 18 / macOS 15.
|
||||
|
||||
[Unreleased]: https://github.com/samsonjs/AsyncMonitor/compare/0.3.1...HEAD
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ import PackageDescription
|
|||
let package = Package(
|
||||
name: "AsyncMonitor",
|
||||
platforms: [
|
||||
.iOS(.v17),
|
||||
.macOS(.v14),
|
||||
.iOS(.v18),
|
||||
.macOS(.v15),
|
||||
],
|
||||
products: [
|
||||
.library(
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ The only way to install this package is with Swift Package Manager (SPM). Please
|
|||
|
||||
### Supported Platforms
|
||||
|
||||
This package is supported on iOS 17.0+ and macOS 14.0+.
|
||||
This package is supported on iOS 18.0+ and macOS 15.0+.
|
||||
|
||||
### Xcode
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Wraps async sequence observation in manageable tasks.
|
|||
|
||||
## Overview
|
||||
|
||||
AsyncMonitor wraps async sequence observation in a `Task` that can be cancelled and stored. It preserves actor isolation on iOS 18+ and includes KVO integration.
|
||||
AsyncMonitor wraps async sequence observation in a `Task` that can be cancelled and stored. It preserves actor isolation and includes KVO integration.
|
||||
|
||||
## Basic Usage
|
||||
|
||||
|
|
@ -91,7 +91,7 @@ sequence.monitor { element in
|
|||
|
||||
## Platform Requirements
|
||||
|
||||
- iOS 17.0+ / macOS 14.0+
|
||||
- iOS 18.0+ / macOS 15.0+
|
||||
- Swift 6.0+
|
||||
|
||||
## Topics
|
||||
|
|
|
|||
|
|
@ -10,18 +10,17 @@
|
|||
/// .monitor { _ in print("Day changed!") }
|
||||
/// ```
|
||||
///
|
||||
/// On iOS 18+, preserves the caller's actor isolation context by default.
|
||||
/// Preserves the caller's actor isolation context by default.
|
||||
///
|
||||
public final class AsyncMonitor: Hashable, AsyncCancellable {
|
||||
let task: Task<Void, Never>
|
||||
|
||||
/// Creates an ``AsyncMonitor`` that observes the provided asynchronous sequence with actor isolation support (iOS 18+).
|
||||
/// Creates an ``AsyncMonitor`` that observes the provided asynchronous sequence.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - isolation: An optional actor isolation context to inherit. Defaults to `#isolation`.
|
||||
/// - sequence: The asynchronous sequence of elements to observe.
|
||||
/// - block: A closure to execute for each element yielded by the sequence.
|
||||
@available(iOS 18, macOS 15, *)
|
||||
public init<Element: Sendable>(
|
||||
isolation: isolated (any Actor)? = #isolation,
|
||||
sequence: any AsyncSequence<Element, Never>,
|
||||
|
|
@ -36,13 +35,12 @@ public final class AsyncMonitor: Hashable, AsyncCancellable {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates an ``AsyncMonitor`` for sequences that may throw errors (iOS 18+).
|
||||
/// Creates an ``AsyncMonitor`` for sequences that may throw errors.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - isolation: An optional actor isolation context to inherit. Defaults to `#isolation`.
|
||||
/// - sequence: The asynchronous sequence of elements to observe. May throw errors.
|
||||
/// - block: A closure to execute for each element yielded by the sequence.
|
||||
@available(iOS 18, macOS 15, *)
|
||||
public init<Element: Sendable, Sequence: AsyncSequence>(
|
||||
isolation: isolated (any Actor)? = #isolation,
|
||||
sequence: Sequence,
|
||||
|
|
@ -61,30 +59,6 @@ public final class AsyncMonitor: Hashable, AsyncCancellable {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates an ``AsyncMonitor`` for iOS 17 compatibility.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - sequence: The asynchronous sequence of elements to observe. Must be `Sendable`.
|
||||
/// - block: A `@Sendable` closure to execute for each element yielded by the sequence.
|
||||
@available(iOS, introduced: 17, obsoleted: 18)
|
||||
@available(macOS, introduced: 14, obsoleted: 15)
|
||||
public init<Element: Sendable, Sequence>(
|
||||
sequence: sending Sequence,
|
||||
@_inheritActorContext performing block: @escaping @Sendable (Element) async -> Void
|
||||
) where Sequence: AsyncSequence & Sendable, Sequence.Element == Element {
|
||||
self.task = Task {
|
||||
do {
|
||||
for try await element in sequence {
|
||||
await block(element)
|
||||
}
|
||||
} catch {
|
||||
guard !Task.isCancelled else { return }
|
||||
|
||||
print("Error iterating over sequence: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
cancel()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
@available(iOS 18, macOS 15, *)
|
||||
public extension AsyncSequence where Element: Sendable, Failure == Never {
|
||||
/// Observes the elements yielded by this sequence and executes the given closure with each element.
|
||||
///
|
||||
|
|
@ -84,7 +83,6 @@ public extension AsyncSequence where Element: Sendable, Failure == Never {
|
|||
}
|
||||
}
|
||||
|
||||
@available(iOS 18, macOS 15, *)
|
||||
public extension AsyncSequence where Element: Sendable {
|
||||
/// Observes the elements yielded by this sequence and executes the given closure with each element.
|
||||
///
|
||||
|
|
@ -163,80 +161,3 @@ public extension AsyncSequence where Element: Sendable {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS, introduced: 17, obsoleted: 18)
|
||||
@available(macOS, introduced: 14, obsoleted: 15)
|
||||
public extension AsyncSequence where Self: Sendable, Element: Sendable {
|
||||
/// Observes the elements yielded by this sequence and executes the given closure with each element (iOS 17 compatibility).
|
||||
///
|
||||
/// This method provides backward compatibility for iOS 17. It requires both the sequence and its elements
|
||||
/// to be `Sendable`, and uses a `@Sendable` closure for thread safety.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - block: A `@Sendable` closure that's executed with each yielded element.
|
||||
///
|
||||
/// - Returns: An ``AsyncMonitor`` that can be stored and cancelled as needed.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```swift
|
||||
/// let cancellable = sendableAsyncSequence.monitor { element in
|
||||
/// print("Received: \(element)")
|
||||
/// }
|
||||
///
|
||||
/// // Store for automatic cleanup
|
||||
/// cancellable.store(in: &cancellables)
|
||||
/// ```
|
||||
///
|
||||
/// - Note: This method is deprecated in iOS 18+ in favour of ``monitor(isolation:_:)``
|
||||
/// which provides better actor isolation support.
|
||||
func monitor(
|
||||
_ block: @escaping @Sendable (Element) async -> Void
|
||||
) -> AsyncMonitor {
|
||||
AsyncMonitor(sequence: self, performing: block)
|
||||
}
|
||||
|
||||
/// Observes the elements yielded by this sequence and executes the given closure with each element and the weakly-captured context object (iOS 17 compatibility).
|
||||
///
|
||||
/// This method provides backward compatibility for iOS 17 with weak reference handling to prevent retain cycles.
|
||||
/// It requires the context to be both `AnyObject` and `Sendable` for thread safety.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - context: The object to capture weakly for use within the closure. Must be `Sendable` and will be
|
||||
/// captured weakly to prevent retain cycles.
|
||||
/// - block: A `@Sendable` closure that's executed with the weakly-captured context and each yielded element.
|
||||
///
|
||||
/// - Returns: An ``AsyncMonitor`` that can be stored and cancelled as needed.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```swift
|
||||
/// class SendableDataManager: Sendable {
|
||||
/// var cancellables: Set<AnyAsyncCancellable> = []
|
||||
///
|
||||
/// func startMonitoring() {
|
||||
/// // Context is weakly captured, preventing retain cycle
|
||||
/// sendableDataStream
|
||||
/// .monitor(context: self) { manager, data in
|
||||
/// manager.process(data)
|
||||
/// }.store(in: &cancellables)
|
||||
/// }
|
||||
///
|
||||
/// func process(_ data: Data) {
|
||||
/// // Process the data
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - Note: This method is deprecated in iOS 18+ in favour of ``monitor(isolation:context:_:)``
|
||||
/// which provides better actor isolation support.
|
||||
func monitor<Context: AnyObject & Sendable>(
|
||||
context: Context,
|
||||
_ block: @escaping @Sendable (Context, Element) async -> Void
|
||||
) -> AsyncMonitor {
|
||||
AsyncMonitor(sequence: self) { [weak context] element in
|
||||
guard let context else { return }
|
||||
await block(context, element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ public extension NSObjectProtocol where Self: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
@available(iOS 18, macOS 15, *)
|
||||
public extension NSObjectProtocol where Self: NSObject {
|
||||
/// Observes changes to the specified key path on the object and executes a handler for each change.
|
||||
///
|
||||
|
|
@ -108,45 +107,3 @@ public extension NSObjectProtocol where Self: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
@available(iOS, introduced: 17, obsoleted: 18)
|
||||
@available(macOS, introduced: 14, obsoleted: 15)
|
||||
public extension NSObjectProtocol where Self: NSObject {
|
||||
/// Observes changes to the specified key path on the object and executes a handler for each change (iOS 17 compatibility).
|
||||
///
|
||||
/// This method provides backward compatibility for iOS 17. It combines KVO observation with ``AsyncMonitor``
|
||||
/// and requires a `@Sendable` closure for thread safety.
|
||||
///
|
||||
/// - Parameters:
|
||||
/// - keyPath: The key path to observe on this object. The value type must be `Sendable`
|
||||
/// to ensure thread safety across async contexts.
|
||||
/// - options: KVO options to use for observation. Defaults to an empty set.
|
||||
/// See `NSKeyValueObservingOptions` for available options.
|
||||
/// - changeHandler: A `@Sendable` closure that's executed with each new value.
|
||||
///
|
||||
/// - Returns: An ``AsyncCancellable`` that can be stored and cancelled as needed.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```swift
|
||||
/// class ProgressObserver {
|
||||
/// var cancellables: Set<AnyAsyncCancellable> = []
|
||||
///
|
||||
/// func observeProgress(_ progress: Progress) {
|
||||
/// progress.monitorValues(for: \.fractionCompleted) { fraction in
|
||||
/// print("Progress: \(fraction.formatted(.percent))")
|
||||
/// }.store(in: &cancellables)
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// - Note: This method is deprecated in iOS 18+ in favour of the non-`@Sendable` version
|
||||
/// which provides better actor isolation support.
|
||||
func monitorValues<Value: Sendable>(
|
||||
for keyPath: KeyPath<Self, Value>,
|
||||
options: NSKeyValueObservingOptions = [],
|
||||
changeHandler: @escaping @Sendable (Value) -> Void
|
||||
) -> any AsyncCancellable {
|
||||
values(for: keyPath, options: options)
|
||||
.monitor(changeHandler)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,6 @@ import Foundation
|
|||
|
||||
// MARK: Basics
|
||||
|
||||
extension Notification: @unchecked @retroactive Sendable {}
|
||||
|
||||
class SimplestVersion {
|
||||
let cancellable = NotificationCenter.default
|
||||
.notifications(named: .NSCalendarDayChanged)
|
||||
|
|
|
|||
Loading…
Reference in a new issue