Search code examples
iosios11uiappearanceios12state-restoration

UIAppearance bug during state restoration


Update

Matt rightly pointed out that my original project had an error with state restoration. However, even after it is removed, I am able to reproduce an issue as long as I am using a table view inside a navigation controller and trying to set isTranslucent property of UINavigationBar to false via an appearance proxy.


For some reason, when iOS restores state, UIAppearance overrides values set in viewDidLoad. It causes me a lot of headaches, and I would like to know how to solve this issue. I view it as a bug.

Here is a small project I created on GitHub to illustrate this issue. When you launch it for the first time, the label's font in ViewController is correctly set to 22 points. However, if you trigger state restoration, it will be 12 points because of the appearance method in willFinishLaunching.

In fact, the cause of this issue is not UILabel.appearance(whenContainedInInstancesOf: [UITableViewCell.self]).font = UIFont.systemFont(ofSize: 12) as I originally thought. Instead, UINavigationBar.appearance(whenContainedInInstancesOf: [GLXNavigationController.self]).isTranslucent = false causes such a behaviour. You can easily verify it yourself.

One way to solve this is to set the font again in layoutSubviews because appearance proxies are applied just before layoutSubviews is called. However, I do not like this approach.

Another possible solution is to set isTranslucent manually for each navigation controller. It is a solution I am opting for, but I still feel that there is a bug with appearance proxy. At a minimum, we should expect consistent behaviour between initial launch and state restoration.

Any help is much appreciated.


Solution

  • You are doing state restoration wrong:

    • Change didFinishLaunchingWithOptions to willFinishLaunchingWithOptions.

    • And make sure that willFinishLaunchingWithOptions contains a call to the window to makeKeyAndVisible, even if it contains nothing else.

    That, along with implementations of shouldSaveApplicationState and shouldRestoreApplicationState, constitutes the rock-bottom boilerplate needed for any implementation of state saving and restoration.