Forgotten UIKit gems: UIAppearance
Tags: ios, swift, ui, uikit
Published: 2021-03-27 19:14:06

# What is `UIAppearance`?

According to Apple docs, `UIAppearance` is "A collection of methods that gives you access to the appearance proxy for a class.".
In simple words, you can modify the `UIAppearance` object that is related to a certain view, and all of the views of that type will be affected. As simple and powerful (and dangerous) as that.
There is another possibility. You can specify that only the views contained in a parent view of type T will be affected by the appearance change.
**Important note:** the `UIAppearance` customization needs to be performed before the views have entered in the `UIWindow`. Otherwise, they won't be affected.

# A practical example

Let's suppose we have this UI:

![Simulator Screen Shot - iPhone 11 - 2021-03-27 at 15.20.54](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7z2i061dpn8d8xt0mwm9.png)

We can change the properties of all the `UILabel` objects in that UI by changing their `UIAppearance`. Let's put this in the `AppDelegate` `application(_:didFinishLaunchingWithOptions:)` method:

```swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    UILabel.appearance().textColor = UIColor.systemGreen
    return true
}
```

![Simulator Screen Shot - iPhone 11 - 2021-03-27 at 15.28.40](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/89pzl6koa03wsswmy367.png)

You can see how simple it is to update the properties in a view using `UIAppearance`.

You may be wondering why the `UILabel` inside `UIButton` haven't been affected. The reason is that those labels are of type `UIButtonLabel`.

In the case we don't want the `UILabel` inside `UITextField` to be affected by the changes in the `UILabel` appearance, we can't do this:

```swift
UILabel.appearance(whenContainedInInstancesOf: [UITextField.self]).textColor = UIColor.lightGray
```

![Simulator Screen Shot - iPhone 11 - 2021-03-27 at 15.46.39](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3p3693f3sd4jnqufsncr.png) 

# How it saved my life this week

To be honest, I've completely forgotten of `UIAppearance` until this week it saved my project.
I had a `WKWebView` where some scroll view indicators were randomly appearing in the middle of the screen.

I wasn't the only one experiencing this problems, as it was also happening in projects like [React Native](https://github.com/facebook/react-native/issues/26610) and [Flutter](https://github.com/flutter/flutter/issues/44174).

Not only that. When I tried to debug the view hierarchy in my `WKWebView`, I found that it was creating other `UIScrollView` subclasses inside of it. And `webView.scrollView` only affected the topmost scroll view.

I tried everything I found in the Github issues I've seen, but nothing worked. Then I remembered `UIAppearance`, and did something like this:

```swift
UIScrollView
    .appearance(whenContainedInInstancesOf: [MyWebView.self])
    .scrollIndicatorInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 1)
```

Adding that immediately fixed all the scroll view inside the web view.

# Caveats

While powerful, applying `UIAppearance` everywhere is a VERY DANGEROUS anti-pattern you should be aware of. It's an extremely powerful tool when it's required, but shouldn't be used more than that.