mirror of
https://github.com/samsonjs/AsyncMonitor.git
synced 2026-03-25 08:25:47 +00:00
Fixes for Swift 6.2 on iOS 26 and macOS 26
This commit is contained in:
parent
33abeebe52
commit
52b10585ab
7 changed files with 25 additions and 18 deletions
|
|
@ -32,8 +32,8 @@ class SimplestVersion {
|
|||
This example uses the context parameter to avoid reference cycles with `self`.
|
||||
|
||||
```swift
|
||||
class WithContext {
|
||||
var cancellables = Set<AnyAsyncCancellable>()
|
||||
final class WithContext: Sendable {
|
||||
nonisolated(unsafe) var cancellables = Set<AnyAsyncCancellable>()
|
||||
|
||||
init() {
|
||||
NotificationCenter.default
|
||||
|
|
@ -55,7 +55,7 @@ class WithContext {
|
|||
Working with Combine publishers is trivial thanks to [`AnyPublisher.values`][values].
|
||||
|
||||
```swift
|
||||
import Combine
|
||||
@preconcurrency import Combine
|
||||
|
||||
class CombineExample {
|
||||
var cancellables = Set<AnyAsyncCancellable>()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public final class AsyncMonitor: Hashable, AsyncCancellable {
|
|||
/// Defaults to `#isolation`, preserving the caller's actor isolation.
|
||||
/// - sequence: The asynchronous sequence of elements to observe.
|
||||
/// - block: A closure to execute for each element yielded by the sequence.
|
||||
@available(iOS 18, *)
|
||||
@available(iOS 18, macOS 15, *)
|
||||
public init<Element: Sendable>(
|
||||
isolation: isolated (any Actor)? = #isolation,
|
||||
sequence: any AsyncSequence<Element, Never>,
|
||||
|
|
@ -41,6 +41,7 @@ public final class AsyncMonitor: Hashable, AsyncCancellable {
|
|||
/// - sequence: The asynchronous sequence of elements to observe.
|
||||
/// - block: A 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
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
@available(iOS 18, *)
|
||||
@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.
|
||||
///
|
||||
|
|
@ -36,6 +36,7 @@ public extension AsyncSequence where Element: Sendable, Failure == Never {
|
|||
}
|
||||
|
||||
@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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ public extension NSObjectProtocol where Self: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
@available(iOS 18, *)
|
||||
@available(iOS 18, macOS 15, *)
|
||||
public extension NSObjectProtocol where Self: NSObject {
|
||||
/// Observes changes to the specified key path on the object and asynchronously yields each value. Values must be `Sendable`.
|
||||
///
|
||||
|
|
@ -44,6 +44,7 @@ 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 asynchronously yields each value. Values must be `Sendable`.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -49,12 +49,12 @@ class AsyncMonitorTests {
|
|||
try await Task.sleep(for: .milliseconds(10))
|
||||
}
|
||||
|
||||
class Owner {
|
||||
let deinitHook: () -> Void
|
||||
final class Owner: Sendable {
|
||||
let deinitHook: @Sendable () -> Void
|
||||
|
||||
private var cancellable: (any AsyncCancellable)?
|
||||
nonisolated(unsafe) private var cancellable: (any AsyncCancellable)?
|
||||
|
||||
init(center: NotificationCenter, deinitHook: @escaping () -> Void) {
|
||||
init(center: NotificationCenter, deinitHook: @escaping @Sendable () -> Void) {
|
||||
self.deinitHook = deinitHook
|
||||
let name = Notification.Name("irrelevant name")
|
||||
cancellable = center.notifications(named: name)
|
||||
|
|
@ -78,8 +78,10 @@ class AsyncMonitorTests {
|
|||
}
|
||||
}
|
||||
|
||||
final class SendableObject: NSObject, Sendable {}
|
||||
|
||||
@Test func stopsCallingBlockWhenContextIsDeallocated() async throws {
|
||||
var context: NSObject? = NSObject()
|
||||
var context: SendableObject? = SendableObject()
|
||||
subject = center.notifications(named: name)
|
||||
.map(\.name)
|
||||
.monitor(context: context!) { context, receivedName in
|
||||
|
|
|
|||
|
|
@ -9,22 +9,22 @@ class AsyncKVOTests {
|
|||
@Test(.timeLimit(.minutes(1)))
|
||||
func monitorValuesYieldsChanges() async throws {
|
||||
let subject = try #require(subject)
|
||||
var values = [Double]()
|
||||
let values = ValueLocker(value: [Double]())
|
||||
let total = 3
|
||||
cancellable = subject.values(for: \.fractionCompleted)
|
||||
.prefix(total)
|
||||
.monitor { progress in
|
||||
values.append(progress)
|
||||
values.modify { $0.append(progress) }
|
||||
}
|
||||
|
||||
for n in 1...total {
|
||||
subject.completedUnitCount += 1
|
||||
while values.count < n {
|
||||
while values.value.count < n {
|
||||
try await Task.sleep(for: .microseconds(2))
|
||||
}
|
||||
}
|
||||
|
||||
#expect(values.count == total)
|
||||
#expect(values.value.count == total)
|
||||
}
|
||||
|
||||
// It's important that the test and the progress-observing task are not on the same actor, so
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ import Foundation
|
|||
|
||||
// MARK: Basics
|
||||
|
||||
extension Notification: @unchecked @retroactive Sendable {}
|
||||
|
||||
class SimplestVersion {
|
||||
let cancellable = NotificationCenter.default
|
||||
.notifications(named: .NSCalendarDayChanged)
|
||||
|
|
@ -12,8 +14,8 @@ class SimplestVersion {
|
|||
}
|
||||
}
|
||||
|
||||
class WithContext {
|
||||
var cancellables = Set<AnyAsyncCancellable>()
|
||||
final class WithContext: Sendable {
|
||||
nonisolated(unsafe) var cancellables = Set<AnyAsyncCancellable>()
|
||||
|
||||
init() {
|
||||
NotificationCenter.default
|
||||
|
|
@ -31,7 +33,7 @@ class WithContext {
|
|||
|
||||
// MARK: - Combine
|
||||
|
||||
import Combine
|
||||
@preconcurrency import Combine
|
||||
|
||||
class CombineExample {
|
||||
var cancellables = Set<AnyAsyncCancellable>()
|
||||
|
|
|
|||
Loading…
Reference in a new issue