Actor `assumeIsolated` erroneously crashes when using a dispatch queue as the underlying executor

You can kind of hack around it:

actor Foo {

    let queue = DispatchSerialQueue(label: "My Foo")

    nonisolated var unownedExecutor: UnownedSerialExecutor {
        queue.asUnownedSerialExecutor()
    }

    private nonisolated func assumeIsolatedHack<T>(
        _ block: (isolated Foo) throws -> T
    ) rethrows -> T where T: Sendable {

        // Before Swift 6, dispatch didn't work well with `Actor.assumeIsolated`.
        // It can report false negatives - where you are actually on the correct queue but 'assumeIsolated'
        // doesn't know it. That was fixed in SE-0424:
        // https://github.com/swiftlang/swift-evolution/blob/main/proposals/0424-custom-isolation-checking-for-serialexecutor.md
        //
        // This feature requires a new version of the Swift runtime, so we need to perform an OS version check
        // and on older systems we need an ugly hack to emulate the new 'assumeIsolated' for Dispatch.

        if #available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, *) {
            return try self.assumeIsolated(block)
        } else {
            dispatchPrecondition(condition: .onQueue(self.queue))
            return try withoutActuallyEscaping(block) {
                let isolationStripped = unsafeBitCast($0, to: ((Foo) throws -> T).self)
                return try isolationStripped(self)
            }
        }
    }
}

Then you can use actors for Obj-C delegates who always get messages posted on the queue you configure them with.