UIAppearance is an underappreciated gem in UIKit’s toolbox. It provides an elegant way to style UI elements globally across your app, thereby keeping your codebase DRY (Don’t Repeat Yourself) and maintainable. In this post, we’ll dive into UIAppearance and learn how to harness its power to style our iOS apps effectively.

What is UIAppearance?

UIAppearance is a protocol in UIKit that allows you to customize the appearance of all instances of a class. You can set global styles for user interface elements, which will be applied to all instances of that class.

To use UIAppearance, you call appearance() on a class that conforms to the protocol. This will return an instance of the class that’s configured to customize the appearance for all of its instances. Here’s a simple example:

UIButton.appearance().tintColor = .blue

In this example, we’re setting the tintColor of all UIButton instances in the app to blue. Now, every button will be blue, unless we override this setting for a specific button.

A Deeper Look at the UIAppearance Protocol

UIAppearance is quite flexible. It allows you to customize various attributes of a UI element, such as colors, fonts, and images. However, it’s important to note that not all properties of a class are stylable using UIAppearance. Only properties marked with UI_APPEARANCE_SELECTOR can be customized.

To see which properties of a class are stylable using UIAppearance, you can refer to the class’s documentation.

UIAppearance Inheritance and Specificity

UIAppearance respects the inheritance hierarchy of classes. If you set an appearance property on a superclass, it will apply to all of its subclasses, unless you override it for a specific subclass.

For instance, if you set the tintColor for UIView, it will apply to all subclasses of UIView (including UIButton, UILabel, etc.), since they inherit from UIView:

UIView.appearance().tintColor = .blue

However, if you want buttons to have a different tintColor, you can override it for UIButton:

UIButton.appearance().tintColor = .green

Now, all UIButtons will be green, but other UIViewa will still be blue.

UIAppearance also allows you to set appearance properties for instances of a class when contained in an instance of a container class. This is done using the appearance(whenContainedInInstancesOf:) method:

UIButton.appearance(whenContainedInInstancesOf: [UINavigationBar.self]).tintColor = .red

In this example, all buttons within a UINavigationBar will be red.

Real World Examples

Let’s look at a more complex example. Suppose we want to style all navigation bars in our app to have a certain look. We can do this using UIAppearance:

UINavigationBar.appearance().barTintColor = UIColor.systemBlue
UINavigationBar.appearance().tintColor = UIColor.white
UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.white]

Now, all navigation bars in our app will have a blue background color, white text, and white buttons.

For a more fine-grained control, we can even target a subclass of a navigation controller. Let’s say we have a subclass called SecondaryNavigationController, and we want its navigation bar to have a different appearance:

UINavigationBar.appearance

(whenContainedInInstancesOf: [SecondaryNavigationController.self]).barTintColor = UIColor.systemPurple
UINavigationBar.appearance(whenContainedInInstancesOf: [SecondaryNavigationController.self]).tintColor = UIColor.black
UINavigationBar.appearance(whenContainedInInstancesOf: [SecondaryNavigationController.self]).titleTextAttributes = [.foregroundColor: UIColor.black]

UIAppearance’s Limitations

Despite its power, UIAppearance is not without limitations. It can only style properties marked with UI_APPEARANCE_SELECTOR, and the changes it makes are global and can only be overridden on a class-by-class basis. Also, its effects are not immediate – they only apply to UI elements that are created after the appearance changes are made.

Additionally, UIAppearance does not work with Swift’s UI framework, SwiftUI. SwiftUI uses a completely different system for styling, which we won’t delve into in this post.

Conclusion

UIAppearance is a powerful tool for styling UI elements globally across your app. Despite its limitations, it’s an excellent way to maintain a consistent look and feel, reduce code duplication, and increase maintainability.