App state restoration doesn't work

With Xcode 11.x, I started to write code that taps into Apple's state restoration features. My apps don't yet use scene delegates and need to work on iOS 12, so just opted to use the iOS 12 set of APIs such as 'application(_:shouldSaveApplicationState:)'.


I started out with a simple test by just implementing the shouldSave and shouldRestore functions in my app delegate. Both return 'true'. Then, for a learning exercise, I instrumented all the app delegate lifecycle APIs (e.g. willEnterForeground) as well as my view controller APIs (viewDidLoad, etc.). Also added the viewController APIs 'encode' and 'decode' functions that just called super and did some logging. Finally, in this simple tab view controller app with two tabs, I set restoration IDs in IB for all three view controllers (tab controller itself and its two children).


When running the app in debug or release mode in the Simulator (iOS 13 runtime), all is well. If I suspend the app, it's definitely calling encode. Stopping the app and relaunching via Xcode then preserves which child view controller I had previously selected.


When running the app on a device with iOS 13.2.2 via Xcode, things worked identically up to the point where I suspended the app (encode called). I force-quit the app on the device, but relaunching it didn't restore its state. The log output revealed that it never called the app delegate's shouldRestoreApplicationState. I also lauched the app directly on the device, but no matter what, it will not restore the last state if lauching it fresh.


On top of this, In some other more advanced samples I wrote, I'm not happy with the NSCoder instance you're given in these callbacks. Their behavior is to trap (crashing your app) instead of generating errors to allow you to gracefully deal with corrupt data. And you cannot set the behavior at this point since that also traps (once a decoder object starts decoding the data, which Apple is obviously doing before calling your delegate API), you cannot switch to the 'generate errors' behavior. To remedy this, one should avoid using APIs such as encodeInteger since if you then call decodeInteger, that will trap if you have bad data. I ended up wrapping Int, Double, Bool in NSNumber and using the encode/decodeObject APIs will thankfully return nil if it cannot find an object for a certain key.


Finally, even if the above simple scenario even worked, it seems to be a decent amount of work to code up both an iOS 12.x and 13.x solution. Thus, I'm going to roll my own solution. Just curious if others have had any success with Apple's APIs. Searching the forums brought up some old posts; some going unanswered.

Replies

This is a late answer, but I'm trying to make App Restoration work with no success. I even only tried using a sample app with a single NavigationController by pushing two different controllers. All have RestorationID assigned. Using iOS 14.

I guess this is bug from Apple? :(