iOS state restoration animation bug - ios

I just wanted to implement the iOS State-Restoration APIs in one of my Apps.
After finally getting it to work, I discovered that a ViewController that I present modally gets restored using an animation, which is not what I want. I would expect my app to just be in the state I left it, but not having the user to see hot he got there.
So I went ahead and downloaded Apple Sample Code on that: https://developer.apple.com/library/ios/samplecode/StateRestore/Introduction/Intro.html and wanted to see if it happens there as well. And it turns out that it does.
Further there is a warning in the Logs:
Unbalanced calls to begin/end appearance transitions for <UINavigationController: 0x7b0512b0>.
Can you tell me if I and obviously Apples Sample Code are doing something wrong, or if it's a bug in iOS?
Btw. I was testing on iOS8
Thanks for any help,
Georg

The following solution comes directly from Apple.
In your app delegate, you should be implementing application:willFinishLaunchingWithOptions: (instead of or in addition to didFinishLaunching). In your implementation, probably as the last line just before returning true (or YES if this is Objective-C), insert this line:
self.window?.makeKeyAndVisible()
Or, if this is Objective-C:
[self.window makeKeyAndVisible];
It turns out that this was always needed, but the documentation has never been clear about it.

From documentation:
Preserving Your App’s Visual Appearance Across Launches
See the 3rd item from the checklist below.
Checklist for Implementing State Preservation and Restoration
Supporting state preservation and restoration requires modifying your app delegate and view controller objects to encode and decode the state information. If your app has any custom views that also have preservable state information, you need to modify those objects too.
When adding state preservation and restoration to your code, use the following list to remind you of the code you need to write.
(Required) Implement the application:shouldSaveApplicationState: and
application:shouldRestoreApplicationState: methods in your app
delegate; see Enabling State Preservation and Restoration in Your
App.
(Required) Assign restoration identifiers to each view controller you
want to preserve by assigning a non empty string to their
restorationIdentifier property; see Marking Your View Controllers for
Preservation.
If you want to save the state of specific views too, assign non empty
strings to their restorationIdentifier properties; see Preserving the
State of Your Views.
(Required) Show your app’s window from the
application:willFinishLaunchingWithOptions: method of your app
delegate. The state restoration machinery needs the window so that it
can restore scroll positions and other relevant bits of your app’s
interface.
Assign restoration classes to the appropriate view controllers. (If
you do not do this, your app delegate is asked to provide the
corresponding view controller at restore time.) See Restoring Your
View Controllers at Launch Time.
(Recommended) Encode and decode the state of your views and view
controllers using the encodeRestorableStateWithCoder: and
decodeRestorableStateWithCoder: methods of those objects; see
Encoding and Decoding Your View Controller’s State.
Encode and decode any version information or additional state
information for your app using the
application:willEncodeRestorableStateWithCoder: and
application:didDecodeRestorableStateWithCoder: methods of your app
delegate; see Preserving Your App’s High-Level State.
Objects that act as data sources for table views and collection views
should implement the UIDataSourceModelAssociation protocol. Although
not required, this protocol helps preserve the selected and visible
items in those types of views. See Implementing Preservation-Friendly
Data Sources.

Apple sample code seems to work fine on Xcode 8.
So I suppose no additional code changes would be required

Related

Should my app be updated to Scene Delegate

Should my app be updated to Scene Delegate from App Delegate. My app supports ios 13.0 and up
first you have to understand what is difference
You could think of them as the global and private versions. One is shared and the other is limited to the individual owner. In a way, they are exactly what you would expect by the names.
Multi-window support is happening
Next time you create a new Xcode project you’ll see your AppDelegate has split in two: AppDelegate.swift and SceneDelegate.swift. This is a result of the new multi-window support that landed with iPadOS, and effectively splits the work of the app delegate in two.
From iOS 13 onwards, your app delegate should:
Set up any data that you need for the duration of the app.
Respond to any events that focus on the app, such as a file being shared with you.
Register for external services, such as push notifications.
Configure your initial scenes.
In contrast, scene delegates are there to handle one instance of your app’s user interface. So, if the user has created two windows showing your app, you have two scenes, both backed by the same app delegate.
Keep in mind that these scenes are designed to work independently from each other. So, your application no longer moves to the background, but instead individual scenes do – the user might move one to the background while keeping another open.
at last I will say that you can go with Scene Delegate
Courtesy of https://www.hackingwithswift.com/articles/193/whats-new-in-ios-13

Quit the application on a specific view

I have a doubt:
I have an app with 10 views. I want that, if the user is on View1 and sends the app to the background, it terminates the application (exit (0)). But I wanted this to happen only on View1, on the other screens, if the app goes to the background and then returns, it will continue where it left off.
What can I do?
Apple's guidelines seem to be strictly against terminating your app programmatically (for example, with exit()); it would go against what iOS users expect of how apps work.
Instead, I recommend the following approach:
When the app is sent to the background (applicationWillResignActive(_:) is called), check which view controller is currently being displayed.
If it's such that you wish to start over next time the app is brought to the foreground, just reset the app window's root view controller to whatever the initial view controller of your app is (typically, it involves reloading the inital view controller from Main.stroyboard, but your setup could be different).
You can not choose at runtime whether your app goes to the background or is terminated when the user presses the home button ("multitasking"); that is set in stone in your Info.plist file at build time.
Also, remember that even if you are in the screen that you wish to preserve when the user resumes, your app might be terminated by the system while it is in the background (to reclaim scarce system resources), so in that case it will still start from the initial screen. To prevent this, you might want to check out the APIs for state preservation and restoration.
Here is another SO question asking how to find the identity of the current view controller. Why not query the current view when you receive applicationWillResignActive indicating that your app is going to move to the background and then choose the action you want?
As far as I understand your description Preserving and Restoring State is what you are looking for.
Excerpt from Documentation:
The preservation and restoration process is mostly automatic, but you need to tell iOS which parts of your app to preserve. The steps for preserving your app’s view controllers are as follows:
Required
Assign restoration identifiers to the view controllers whose
configuration you want to preserve; see Tagging View Controllers for
Preservation.
Tell iOS how to create or locate new view controller objects at
launch time; see Restoring View Controllers at Launch Time.
Optional
For each view controller, store any specific configuration data needed to return that view controller to its original configuration; see Encoding and Decoding Your View Controller’s State.
Here is a link to Preserving Your App’s Visual Appearance Across Launches

Save UIViewController and display again if needed

I am trying to create a system where a user can open a UIViewController, close out of that ViewController, and return to the same ViewController if they closed it by accident. The UIViewController is populated with data from the internet (that changes frequently) and is a long scrolling UITableView. Currently when the user enters the same UIViewController again, the data is lost and must be re-downloaded, and their previous position is lost.
On the Android version of my app, I have a ViewPager as the main view, with the main pane being the left Fragment and the opened pane as the right Fragment. When the user opens the same "submission", the Fragment is not re-created and the user returns to the same screen, and if the user clicks a new submission, the old Fragment is deleted and a new one is loaded in its place. This allows for the state to be the same and the user can go back if they closed out of the pane by accident.
I think keeping a static version of the UIViewController would be bad practice and lead to memory issues down the road, but I cannot think of another way to implement this. Any suggestions would be appreciated.
You should read up on Apple's docs on restoring view controller state: https://developer.apple.com/library/content/featuredarticles/ViewControllerPGforiPhoneOS/PreservingandRestoringState.html
Additionally, you will need to archive and unarchive the data being displayed in your view controller. Therefore you might want to implement the NSCoding protocol in your model classes. Once you've implemented NSCoder, you can use NSKeyedArchiver / NSKeyedUnarchiver to save and restore state for your view controller. Read up on NSCoding here: https://developer.apple.com/reference/foundation/nscoding
Finally the App Delegate sends out notifications when your app is about to terminate or move to the background. So in this class you will need to start the whole process of saving and restoring application state. Read up on UIApplicationDelegate here: https://developer.apple.com/reference/uikit/uiapplicationdelegate

Implement state restoration for an app that has been built already

I want some advice on how to properly take on implementing state preservation and restoration for an app that has been build already, having lot of view controllers and complex hierarchy.
What are the things to be kept in mind when trying to preserve state for an app that is running for a while already?
EDIT:
I want to get clarified or possibly get a solution to a problem that I am facing in terms of restoring state goes. I successfully restore app' state on launch. I restore a view controller and other view controllers in hierarchy. Now when I push another view controller and sequence of other view controllers to nav. stack, at a particular view controller, for some reason the app crashes due to an exception. So when I open the app back, it still restores the first view controller's state that was preserved when pressing home button.
Specifically I want to know if there is any way to discard app state info. when app terminates due to uncaught exception? I know that the state will be discarded if user manually force kills app, or state restoration fails, or the app terminates at launch. Is there a way to catch a termination and configure app state accordingly? Suggestions would be great. Thanks.
From my understanding, state restoration should be done as we move along building the app
No, I don't think that's right at all. The whole beauty of the built-in state saving-and-restoration mechanism is that it can be patched right onto the working app, one view controller at a time. You don't even have to complete it for the whole app before testing; on the contrary, another beauty of the mechanism is that it works for just the subset of the view controller hierarchy for which it is in fact implemented, with no harm done to the rest of the app. So just start at the top of the view controller hierarchy and start implementing it.

IOS initial view controller based on condition retrieved from database

An iOS app I'm creating shows a setup screen upon first launch which requires data to be written to the database.
Upon launch, I need to access this value form the database.
If it is set, launch main view controller
Else show setup view controller.
As far as I'm aware theres two ways I can do this, programmatically setting it from the AppDelegate or using an initial View Controller as a splash screen and performing the look up and segue there.
What would be the best way to approach this? Is it wrong to do a database lookup in didFinishLaunchingWithOptions?
Using a splash screen is probably the better option as it provides better scope for modification in the future and allows you to update the user on progress. It is fine for the app delegate to run logic to determine how the app starts but you should endeavour to keep the app delegate minimal and focussed.
I very much doubt that you would get this approved (if your goal is the App Store). Your app delegate needs to create a window, and set a rootViewController to that window before it returns YES in appFinishLaunching:
You simply do not have enough time to check with a server before creating the first viewController and you'll be creating poor interface if you try. I suggest the first ViewController will need to be informing the user that it is checking with the server with an activityIndicator or something. The best :)

Resources