diff --git a/RealmSwift/Aliases.swift b/RealmSwift/Aliases.swift index 24d72621e3..25cb6804f0 100644 --- a/RealmSwift/Aliases.swift +++ b/RealmSwift/Aliases.swift @@ -94,10 +94,8 @@ extension ObjectBase { let token = RLMObjectNotificationToken() token.observe(self, keyPaths: keyPaths) { object, names, oldValues, newValues, error in assert(error == nil) - assumeOnActorExecutor(actor) { actor in - block(actor, .init(object: object as? T, names: names, + actor.invokeIsolated(block, .init(object: object as? T, names: names, oldValues: oldValues, newValues: newValues)) - } } await withTaskCancellationHandler(operation: token.registrationComplete, onCancel: { token.invalidate() }) diff --git a/RealmSwift/Impl/RealmCollectionImpl.swift b/RealmSwift/Impl/RealmCollectionImpl.swift index 5957147b25..4ac3e34bb6 100644 --- a/RealmSwift/Impl/RealmCollectionImpl.swift +++ b/RealmSwift/Impl/RealmCollectionImpl.swift @@ -128,9 +128,7 @@ extension RealmCollectionImpl { ) async -> NotificationToken { await with(self, on: actor) { actor, collection in collection.observe(keyPaths: keyPaths, on: nil) { change in - assumeOnActorExecutor(actor) { actor in - block(actor, change) - } + actor.invokeIsolated(block, change) } } ?? NotificationToken() } diff --git a/RealmSwift/Map.swift b/RealmSwift/Map.swift index 88274cefcd..4f5d48af25 100644 --- a/RealmSwift/Map.swift +++ b/RealmSwift/Map.swift @@ -607,9 +607,7 @@ public final class Map: RLMSwiftColle ) async -> NotificationToken { await with(self, on: actor) { actor, collection in collection.observe(keyPaths: keyPaths, on: nil) { change in - assumeOnActorExecutor(actor) { actor in - block(actor, change) - } + actor.invokeIsolated(block, change) } } ?? NotificationToken() } diff --git a/RealmSwift/Projection.swift b/RealmSwift/Projection.swift index 60a4101765..73e3b42f82 100644 --- a/RealmSwift/Projection.swift +++ b/RealmSwift/Projection.swift @@ -536,9 +536,7 @@ extension ProjectionObservable { ) async -> NotificationToken { await with(self, on: actor) { actor, obj in obj.observe(keyPaths: keyPaths, on: nil) { (change: ObjectChange) in - assumeOnActorExecutor(actor) { actor in - block(actor, change) - } + actor.invokeIsolated(block, change) } } ?? NotificationToken() } diff --git a/RealmSwift/SectionedResults.swift b/RealmSwift/SectionedResults.swift index acbe569411..04cd203393 100644 --- a/RealmSwift/SectionedResults.swift +++ b/RealmSwift/SectionedResults.swift @@ -206,9 +206,7 @@ public extension RealmSectionedResult { ) async -> NotificationToken { await with(self, on: actor) { actor, collection in collection.observe(keyPaths: keyPaths, on: nil) { change in - assumeOnActorExecutor(actor) { actor in - block(actor, change) - } + actor.invokeIsolated(block, change) } } ?? NotificationToken() } diff --git a/RealmSwift/Util.swift b/RealmSwift/Util.swift index d5b600db09..7a6e29df33 100644 --- a/RealmSwift/Util.swift +++ b/RealmSwift/Util.swift @@ -160,30 +160,43 @@ internal func logRuntimeIssue(_ message: StaticString) { } } +@available(macOS 10.15, tvOS 13.0, iOS 13.0, watchOS 6.0, *) @_unavailableFromAsync -internal func assumeOnMainActorExecutor(_ operation: @MainActor () throws -> T, - file: StaticString = #fileID, line: UInt = #line -) rethrows -> T { +internal func assumeOnMainActorExecutor(_ operation: @MainActor () throws -> Void, + file: StaticString = #fileID, line: UInt = #line +) rethrows { +#if compiler(>=5.10) + // This is backdeployable in Xcode 15.3+, but not 15.1 + try MainActor.assumeIsolated(operation) +#else if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { return try MainActor.assumeIsolated(operation) } precondition(Thread.isMainThread, file: file, line: line) return try withoutActuallyEscaping(operation) { fn in - try unsafeBitCast(fn, to: (() throws -> T).self)() + try unsafeBitCast(fn, to: (() throws -> ()).self)() } +#endif } -@_unavailableFromAsync @available(macOS 10.15, tvOS 13.0, iOS 13.0, watchOS 6.0, *) -internal func assumeOnActorExecutor(_ actor: A, - _ operation: (isolated A) throws -> T -) rethrows -> T { - if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { - return try actor.assumeIsolated(operation) - } +extension Actor { + @_unavailableFromAsync + internal func invokeIsolated(_ operation: (isolated Self, Arg) throws -> Ret, _ arg: Arg, + file: StaticString = #fileID, line: UInt = #line + ) rethrows -> Ret { +#if compiler(>=5.10) + // This is backdeployable in Xcode 15.3+, but not 15.1 + preconditionIsolated(file: file, line: line) +#else + if #available(macOS 14.0, iOS 17.0, watchOS 10.0, tvOS 17.0, *) { + preconditionIsolated(file: file, line: line) + } +#endif - return try withoutActuallyEscaping(operation) { fn in - try unsafeBitCast(fn, to: ((A) throws -> T).self)(actor) + return try withoutActuallyEscaping(operation) { fn in + try unsafeBitCast(fn, to: ((Self, Arg) throws -> Ret).self)(self, arg) + } } }