Skip to content

Instantly share code, notes, and snippets.

@siracusa
Last active June 17, 2024 16:47
Show Gist options
  • Save siracusa/137e3fae8a384ac4bda8c56524826d6b to your computer and use it in GitHub Desktop.
Save siracusa/137e3fae8a384ac4bda8c56524826d6b to your computer and use it in GitHub Desktop.
Swift Concurrency Candidate
NSWorkspace.shared.notificationCenter.addObserver(
forName: NSWorkspace.didLaunchApplicationNotification,
object: nil, queue: nil, using: { [weak self] notification in
self?.doStuff()
})
@mattmassicotte
Copy link

Oh well actually yes, you can achieve something similar in Swift:

extension NotificationCenter {
    @MainActor
    public func addMainActorObserver(
        forName name: Notification.Name,
        object obj: Any? = nil,
        block: @escaping @MainActor (Notification) -> Void
    ) -> any NSObjectProtocol {
        // this let's you lie to the compiler!
        let sendableBlock = unsafeBitCast(block, to: (@Sendable (Notification) -> Void).self)

        return self.addObserver(forName: name, object: obj, queue: .main, using: sendableBlock)
    }
}

I'm not sure exactly what's up with the NS_SWIFT_UI_ACTOR. I haven't looked into the clang annotations deeply but they are definitely supposed to work. Please file a bug if something isn't working as it should!

@danielpunkass
Copy link

Perfect, thanks for the bitcast hack! And I'll look into the NS_SWIFT_UI_ACTOR issue and file a bug if it's busted.

@danielpunkass
Copy link

Also for anybody reading along: I think I decided I don't want/need the addMainActorObserver to be @MainActor. It's likely I'll only ever call it from the main thread, but because the method guarantees delivery on the main thread, it can be safely called from anywhere, I think.

@mattmassicotte
Copy link

I think this is correct! But, I also do want to point out that this version makes it possible to pass data unsafely across threads by way of the Notification object. I don't think that's likely though.

@danielpunkass
Copy link

Oh, right. That's a good point. Maybe I should leave it @MainActor after all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment