Search code examples
cocoansattributedstringnstextviewnscolor

Replacing NSColor with another in NSAttributedString


I am trying to replace one color with another in NSAttributedString to enable a dark mode in a pre-Mojave-app. I have a long NSTextView which holds the string.

Is there any way to remap or mutate the color that is already set in the NSTextView, similar to what the Mojave dark mode does with NSColor.textColor? If there are multiple documents open, formatting the string by enumerating through ranges and attributes one by one is very slow.

Hints & tips using Swift or Objective-C are greatly appreciated!


Solution

  • Short Answer: Make your own "adaptable" colors.

    Long Answer

    • Make a subclass of NSColor which has two readonly (to keep with NSColor being immutable) instance NSColor properties for the standard and dark colors.

    • Add a class property to get/set which color should be used.

    • Define your own init/new methods which take the underlying standard and dark colors.

    • Add all of NSColor's creation methods to your colors @interface marking them all NS_UNAVAILBLE – this prevents accidental use of them.

    • Override all the methods required – see NSColor.h (use "Jump to Definition" in Xcode to open it). Each override simply directs the method to the appropriate standard or dark color. This is just a bunch of boilerplate code.

    • Now use your subclass to color your NSAttributedString. When you wish to switch mode use the class property to switch all the colors on-the-fly and redraw your string.

    HTH