Component #1: Applying your Theme

First, I want to address how to apply your theme, by explaining how not to apply your theme, via what is probably the most popular way to apply your theme, using UIAppearance .

Not all that is UI can be controlled by UIAppearance in the first place.

UIAppearance 😖

If you Google search how to implement a night mode, it’s likely UIAppearance has been recommended to you. In fact, many have made tutorials on how to use UIAppearance to support themes, and I don’t blame them. Why use it? Because it’s easy. UIAppearance is like the Storyboard of UI code, easy for simple things, but it has poor customization and scalability.

Appearance selectors start off simply. Let’s assume we want all our UILabel s to have a particular text color. You might then call this upon applicationDidFinishLaunching: :

[[UILabel appearance] setTextColor:textColor];

Great! 🙃 Every label that appears will now have that text color . But of course, we don’t want all of our labels to have that color. Some need color A, others color B, etc, etc. There are strategies to achieving this:

[[TitleLabelSubclass appearance] setTextColor:titleColor];

[[SubtitleLabelSubclass appearance] setTextColor:subtitleColor];

By subclassing UILabel , you can specify different appearance attributes to different labels. Why do I hate this? Because not only is it obnoxious to ensure every label is the proper subclass for its appearance, it prevents me from using custom functional subclasses as needed, without again accounting for appearance.

UIAppearance is like the Storyboard of UI code

And although there are more appearance selectors which provide more control ( appearanceForTraitCollection: , appearanceWhenContainedInInstancesOfClasses: ), you’ll end up overfitting everything to work, and still being unable to accomplish certain tasks. After all, not all that is UI can be controlled by UIAppearance in the first place.

Finally, if the theme changes during runtime, the method to reapply appearance changes is one which makes me cringe, by removing and re-adding all subviews of your application’s windows.

So what’s an iOS developer to do?