Capture of 'self' with non-sendable type 'AppDelegate' in a `@Sendable` closure

I don't understand the reason of this error after switching to Xcode 16, Swift 6 language version.

My simplified code looks like this:

class AppDelegate: NSObject, NSApplicationDelegate {    
    var window: NSWindow!
    let windowInfo = WindowInfo()
    
    func applicationDidFinishLaunching(_ aNotification: Notification) {
        window = NSWindow( … )   // Create the window and set the content view.

        Task { @MainActor in
            NotificationCenter.default.addObserver(forName: NSWindow.didMoveNotification, object: nil, queue: nil)   { [self] (notification) in windowInfo.windowFrame = window.frame }
            NotificationCenter.default.addObserver(forName: NSWindow.didResizeNotification, object: nil, queue: nil) { [self] (notification) in windowInfo.windowFrame = window.frame }
        }
    }
}

I did already add a Task(…) to make sure to be on MainActor but following error remains:

Capture of 'self' with non-sendable type 'AppDelegate' in a `@Sendable` closure
      Class 'AppDelegate' does not conform to the 'Sendable' protocol

Any clue how to solve this issue?

1 Like

NSApplicationDelegate does not automatically make your type MainActor. I believe you can address this by removing the Task and instead marking your type @MainActor.

I also think this is quite annoying, especially since UIApplicationDelegate does use @MainActor. I've filed a bug about this previously: FB13883653.

1 Like

Thanks for your reply.
I added the Task to get rid of Actor issues but a change to

    @MainActor func applicationDidFinishLaunching(_ aNotification: Notification) {
…
    NotificationCenter.default.addObserver(forName: NSWindow.didMoveNotification, object: nil, queue: nil)   { [self] (notification) in windowInfo.windowFrame = window.frame }
    NotificationCenter.default.addObserver(forName: NSWindow.didResizeNotification, object: nil, queue: nil) { [self] (notification) in windowInfo.windowFrame = window.frame }
}

gives still the errors

Capture of 'self' with non-sendable type 'AppDelegate' in a *@Sendable closure
Class 'AppDelegate' does not conform to the 'Sendable' protocol

for windowInfo and

Main actor-isolated property 'frame' can not be referenced from a Sendable closure
Property declared here (AppKit.NSWindow)

for window.frame.

Both window and windowInfo are declared in the AppDelegate class.

I guess a different way to declare is needed…

Sorry, I wasn't clear!

If you look at the definition of applicationDidFinishLaunching, you'll see that it is marked @MainActor already. That is actually the problem. Your AppDelegate type is not.

Try this:

@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {  
// ...
}

This exact problem isn't covered by the migration guide, but the concept is and a similar problem is presented. Might be worth checking out.

https://www.swift.org/migration/documentation/swift-6-concurrency-migration-guide/commonproblems#Latent-Isolation

1 Like

May thanks. I did a quick look at the provided link and it looks promising…

1 Like

Got it working in Swift 6 language mode.
I made following changes:

Added @MainActor:

@MainActor
class AppDelegate: NSObject, NSApplicationDelegate {
…
}

The notification code is now running in a Task:

NotificationCenter.default.addObserver(forName: NSWindow.didMoveNotification, object: nil, queue: .main) {  [self] (notification) in
    Task { @MainActor in
        windowInfo.windowFrame = window.frame
    }
}

Many thanks for your help which did lead me to a solution.

1 Like