Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manually invoke state preservation in iOS 6 and onwards

Some background

I'm working on an iOS app where we want the state of the application to be preserved.
Before this app is out, iOS 7 is likely to have been released or is soon to be released and the majority seems to have moved away from iOS 5. We have therefore decided to develop for iOS 6 an onwards.

In iOS 6 there are some really nice functionality for preserving state. Just give all views in the storyboard unique IDs and implement these two functions in the "AppDelegate":

- (BOOL)application:(UIApplication*)application shouldSaveApplicationState:(NSCoder*)coder;
- (BOOL)application:(UIApplication*)application shouldRestoreApplicationState:(NSCoder*)coder;

iOS will then "automagically" preserve the navigation history of the app. The methods:

- (void)encodeRestorableStateWithCoder:(NSCoder*)coder;
- (void)decodeRestorableStateWithCoder:(NSCoder*)coder;

can then be used to store and retrieve data.
No problems there it works without issues. But, the methods that save the state are only triggered when the app entered the background.

Let's say we have one NavigationController with four ViewControllers: A, B, C and D. The user navigates from A to B, in B he switches over to Safari to google something. The application state is saved in B. The user then switches back to the app and navigates on to C and then to D. In D the app unfortunately encounters an exception and goes down. When the user restarts the app, iOS will try to restore the saved state. This state however, was saved in B. Which means that when the app launches, it doesn't start from the beginning, not where the user left it (D) and not even the previous view (C) but in B.

A possible solution

The above scenario could be avoided if the app saved its state at every new view. However there aren't (as far as I know) any public methods to trigger the state preservation process. I have examined the call stack while debugging and found out that iOS calls the following method on the UIApplication object in iOS 6:

_saveApplicationPreservationState:

and the following method in iOS 7:

_saveApplicationPreservationState:viewController:sessionIdentifier:beginHandler:completionHandler:

There also seems to be another method that calls one of the above depending on the iOS version:

_saveApplicationPreservationStateIfSupported

By invoking this method like this:

    if ([[UIApplication sharedApplication] respondsToSelector:@selector(_saveApplicationPreservationStateIfSupported)])
        [[UIApplication sharedApplication] performSelector:@selector(_saveApplicationPreservationStateIfSupported)];

I can see that the expected methods are called.

The actual question

If I would go with the above solution could that get my app rejected from the App Store? I mean technically it's not a private method, it's just not exposed. By wrapping the call in "respondsToSelector" the app won't crash if the APIs are changed, it just won't save the state as often. But if it could get the app rejected it's not an option. Or is there any other way to manually invoke the state preservation process other than the one described above? I would be nice to be able to use the built-in functionality rather than building a custom solution that saves the state to NSUserDefaults.

like image 415
Ryuu Tora Avatar asked Jun 17 '13 11:06

Ryuu Tora


1 Answers

Event if the question is already 2 years old, i'll try my luck. Btw op, i guess, you'll have most likely solved it by now.

You're gonna for sure get rejected. They are scanning the sourcecode for methods you are calling. I had this several times, back when i was using the UDID methods. Hope it helped.

like image 129
Sven Holzinger Avatar answered Sep 18 '22 17:09

Sven Holzinger