NSTextView draws black on almost-black in Dark Mode

I noticed that the errant text views have their "attributed string" bound, with Cocoa Bindings, to methods which return plain, not attributed NSString objects. I probably did this because I was lazy when I wrote this app years ago, and it worked fine. This mismatch turned out to be the problem. The fix is to modify these methods to return a NSAttributedString, with an attribute dictionary containing the key/value pair

NSForegroundColorAttributeName : NSColor.controlTextColor

Probably what happened is that Cocoa was designed to do what you probably want when a attributed string binding gets a non-attributed string. Instead of barfing an exception, Cocoa applies some "default" attributes, which include the black text color which has been the macOS default since 1984 – totally sensible until Dark Mode came along! Well, it might have been nice of Apple to change this default from black to controlTextColor, but apparently they did not.

Conclusion: We can no longer get away with binding the attributed string of a text view to a plain non-attributed string.

Or, you can use the answer of @Ely and bind to value. But if you try that, and do not see a value binding in the Bindings Inspector, but do see a data binding, it is because of these remarks in the NSTextField documentation:

[value] binding is only available when the NSTextView is configured to display using as a single font.

and later

[data] binding is only available when the NSTextView is configured to allow multiple fonts.

It turns what they mean by configured to allow multiple fonts is that, in the Attributes inspector, the Allows Rich Text checkbox is on. Conversely, configured to display using as a single font means that the Allows Rich Text checkbox is off.


It worked for me after using this code (macOS Catalina version 10.15.3):

if #available(OSX 10.14, *) {         
    textView.usesAdaptiveColorMappingForDarkAppearance = true
} else {
    // Fallback on earlier versions - do nothing
}

I found this documented in the method:

/*************************** Dark Mode ***************************

When YES, enables the adaptive color mapping mode. In this mode under the dark effective appearance, NSTextView maps all colors with NSColorTypeComponentBased by inverting the brightness whenever they are coming in and out of the model object, NSTextStorage. For example, when rendering, interacting with NSColorPanel and NSFontManager, and converting from/to the pasteboard and external formats, the color values are converted between the model and rendering contexts. Note that the color conversion algorithm compresses the brightness range and, therefore, does not retain the round-trip fidelity between the light and dark appearances. It may not be suitable for rich text authoring, so it is a good idea to provide a command or preference for your users to see and edit their docs without this option, or in light mode. */