I have a macOS app that runs only in the macOS status bar. I changed the "Application is agent (UIElement)" property in the Info.plist to "YES":
<key>LSUIElement</key>
<true/>
I have a timer that prints out the appearance's name every 5 seconds like this:
Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { _ in
    let appearance = NSAppearance.currentDrawing()
    print(appearance.name)
}
Problem
The name doesn't actually change when I toggle dark/light mode in system settings. It always prints the name of the appearance that was set when the application launched.
Is there a way to listen to system appearance changes?
Goal
My end goal is actually to draw an NSAttributedString to an NSImage, and use that NSImage as the NSStatusItem button's image.
let image: NSImage = // generate image
statusItem.button?.image = image
For the text in the attributed string I use UIColor.labelColor that is supposed to be based on the system appearance. However it seems to not respect the system appearance change.
When I start the application in Dark Mode and then switch to Light Mode:
When I start the application in Light Mode and then switch to Dark Mode:
Side note
The reason why I turn the NSAttributedString into an NSImage and don't use the NSAttributedString directly on the NSStatusItem button's attributedTitle is because it doesn't position correctly in the status bar.




 
                        
The problem with drawing a
NSAttributedStringis, thatNSAttributedStringdoesn't know how to render dynamic colors such asNSColor.labelColor. Thus, it doesn't react on appearance changes. You have to use a UI element.Solution
I solved this problem by passing the
NSAttributedStringto aNSTextFieldand draw that into anNSImage. Works perfectly fine.React on NSAppearance changes
In addition, since
NSImagedoesn't know aboutNSAppearanceeither I need to trigger a redraw on appearance changes by observing theeffectiveAppearanceproperty of the button of theNSStatusItem: