iOS 4 Application Termination and Undo - iphone

What is a good way to handle iOS 4 app termination when using an NSUndoManager?
I have an iPhone (iOS 4) application that uses Core Data. The app allows the user to edit managed objects, and I implement undo using NSUndoManager in a straightforward manner: Before displaying an editor view modally, I create a new NSUndoManager for the managed object context. I also begin undo grouping so that any changes can easily be undone if the user taps the "Cancel" button. If the user taps "Save," I simply remove the undo manager and the changes become permanent. So far, so good.
If the user presses the Home button (or takes a call) in the midst of editing an object, the app gets suspended. It sends the app delegate an applicationDidEnterBackground message and I use that opportunity to save the managed object context. The context, of course, contains the new edits, just waiting to be undone by the NSUndoManager.
Here's the issue: If the app is later "unsuspended," the NSUndoManager still exists and everything works fine. However, if the app gets "killed in its sleep" by the OS, the undo stack is lost and the changes made to the object now become permanent. At relaunch I want to restore the app to the exact same state it was in before it was suspended, but that seems to require me to save and restore the undo stack. Unfortunately, I couldn't find an obvious way to do that.
Is there a good way to support undo so that it works consistently whether or not an app is terminated? I hope I'm missing something obvious. Any help or suggestions would be appreciated.

You can spend all the time in the world serializing your current app state to disk so you can relaunch where you left off...
... or you can sidestep the issue by reducing your memory footprint so you're less likely to be killed while in the background. I suspect the backgrounded-due-to-phonecall app is given priority over other background apps, if only because it is more recently used.
Low memory, updating the app, or tapping the box in the task switcher can all kill your app. It's up to you to decide whether you need to preserve the exact state the app was in. I think Android only preserves the serialized app state for about 30 minutes, because short-term memories don't tend to last much longer.
(What? .foo.txt.swp exists? It's several months old! How am I supposed to know where it's from? Why can't you just show me the changes between that and foo.txt so I can decide whether I want to keep it?)

Related

Execute code upon app termination in swift

I'm new to swift and programming so I'm not sure if or how this is possible, but could anyone tell me if I can designate code to be executed when the user terminates the app from the multitasking menu? I just have a line of code that I would like to execute at that time, but I'm not sure where to put it in my project.
Thanks!
If the user terminates the app from the multitasking menu, your app is killed dead. It is not terminated "in good order". You do not get an event at that time. It's just like the scene in 2001: A Space Odyssey where the scientists are already in suspended animation and HAL pulls the plug on them.
The art of Cocoa / iOS 8 programming is the art of the possible. Adjust your desires to fit the reality of the events you do get. You get an event when the user leaves your app, so if there is something you need to be sure to do, do it then, as you may never get another chance.
As matt said, when the app is terminated from the multitasking menu, none of your code is run, it's just killed.
Try putting your code into the application delegate's applicationWillResignActive(_:) method. This will run any time your app becomes inactive, though. In other words, more often (all the time) than being terminated in the multitasking menu. It'll run when there's an incoming phone call or text, I believe it will run if there is a notification with an alert, it will run when the user presses the home button.

Monitoring regions but location icon disappears when app is killed

I have a CLLocationManager contained in a singleton and I have added around a dozen regions to monitor. I am successfully notified of boundary crossings when the app is in the foreground/background. However, when I force quit the app, the location icon disappears and I am not getting any callbacks.
As far as I can see, this is intended functionality as of iOS7. Here is a reply I found to a similar question, in this case involving significant location change: https://devforums.apple.com/message/882691#882691:
If a user swipes up in the app switcher then the OS will not launch the app unless explicitly told to do so by the user. So no, SLC will not be launching the app, nor will silent notifications. The only thing that will launch the app at that point is the user tapping the icon. The intention here is that the user has expressed their choice of not having that app running any more for any reason, so we honor that.
In this situation, there's really nothing that you can do. The next time the user launches the app you can let them know that some of the data may be missing, although you really cannot tell whether there's missing data or not (i.e. you might have been killed by the OS in the background and the user may not have moved thereby not triggering any SLC notifications). My suggestion would be to gather the data you can within the policies of the OS and if the user has manually killed the app then respect that wish and don't do anything.
By all means, feel free to file a bug report if this change in behavior winds up causing problems for you or (especially) confusion for your users.

Unable to get Force Quit event in iOS when background process is allowed, How to do?

After iOS 3.2, Apple allowed us to keep running our application in background mode. Using the same concept, in my application I have downloading functionality implemented which runs over in background mode.
The problem is that whenever I force quit my app manually, (Double tap on home button > long tap on app icon > tap on cross button of app) as per Apple specifications. I am not able to track that event in code, hence I am unable to track my downloading data.
Because of that, my data is being lost. So how to track this and track/save data before it gets force quitted.
Reference: AppDelegate Protocol
As far as I know, there is no way to handle that event, since it kills the whole process immediately.
You will need to save your data periodically or just leave it like it is. User killing apps, should be aware of that he is killing apps.
track each 'chunk of data' as you receive it and you write it to disk. that way you don't have to rely on a shutdown event
Thats how ASI and AFN do it and thats how you could also manually do it using NSURLConnection directly.
On startup, see if and how much of the data you already have in the file. Again ASI and AFN make this really easy!

Prevent app from shutting down when device is rebooted

When I restart the device my app is on it won't preserve the state it had once I open up the app again, it will be as if it's the first time I open, losing the session and having to re-login, how can I make my app preserve its state even through a device reboot? Like Twitter does, for example.
I'll try a bit more formal answer based on the comments you added above. I'll start by saying that the link Tim posted is something you should familiarize yourself with.
When your app is running, it's in the Foreground state. When you "exit" an app with the Home button, you're not really quitting it; you're just pushing it to the Background state. after a few seconds in background state, the OS automatically moves the app to the Suspended state. If you come back within a few minutes, your app is still in memory, so the OS just puts it back on the screen the way it was.
However, if you leave the app alone for a while and use other apps, the OS can--at any time and without warning--purge your app from memory. This is known as the "Not Running" state. Now, when the open the app again, it has to start from scratch. Obviously, the same thing happens when the device restarts--all apps are purged from memory.
The trick, then, is to save essential information about the app state whenever it enters the background state. You can use the app delegate's didEnterBackground method, or register for the UIApplicationDidEnterBackgroundNotification and invoke a method in your active view controller (or any other class, for that matter). Either way, you should save whatever state information you can.
How do you save this information? There are several strategies. For a simple app, perhaps you can register a few setting as NSUserDefaults. Or maybe you can write out a file containing whatever data the user was working on. It's really up to you.
Then, whenever the app launches, check for the presence of that saved data (however you chose to write it out), and set up the UI accordingly. To the user, it will appear as though the app never quit, which is exactly what Apple wants them to think.

Handling app termination during core data background population

I've looked around at answers to questions regarding executing core data saves in the background, but none that I've found have directly addressed the following scenario:
I've set up core data so that when my app launches for the first time, core data is populated from a plist and then saved to the persistent store (all on a background thread). During this time, the app displays a "please wait" popup with an animating activity indicator. This seems to work nicely and generally the app will finish the population even if the user hits the home button during the population, pushing the app to the background. However, it is possible that the app could be completely terminated before this population finishes (I've successfully done this by hitting home, double-tapping home, and removing the app from the multi-tasking tray really really fast). In this scenario, the app quits without saving the data to the store. On the next launch of the app, the app recognizes that the store already exists, so it doesn't populate, thus leaving the user with a completely empty database. So the question(s) is/are:
Is there a way to completely remove the store on app termination if the population hasn't finished? I attempted to do this in -applicationWillTerminate: which didn't seem to properly recognize if the app was in the middle of populating.
Or, is there a better way to recognize when the store requires population? E.g., can I determine if the store is empty upon launch?
I would suggest this general approach to your problem:
at the end of the population phase, write a flag to your core data base or to your app defaults (NSUserDefaults);
(now, when the app is terminated before finishing the population phase, the flag will not be stored);
at startup, check for that flag; if it is there, you know that the population phase completed, otherwise you know something went wrong.
Of course, there is a slight chance that the app is terminated just after the population phase is done and before the flag is stored; aside from this event to be pretty unlikely, in any case, if that happened, it would only force your app to populate the data once again at the next launch, but will not be cause of any data consistency issue.
A more specific approach is base on the use of beginBackgroundTaskWithExpirationHandler:
Your app delegate’s applicationDidEnterBackground: method has approximately 5 seconds to finish any tasks and return. In practice, this method should return as quickly as possible. If the method does not return before time runs out, your app is killed and purged from memory. If you still need more time to perform tasks, call the beginBackgroundTaskWithExpirationHandler: method to request background execution time and then start any long-running tasks in a secondary thread. Regardless of whether you start any background tasks, the applicationDidEnterBackground: method must still exit within 5 seconds.
This will allow you to get more time to complete the population phase before the app is terminated in any "non-pathological" case (i.e., it will not work if the user kills the app like you did in your test, and will not be safe in case something goes wrong in the app itself and it crashes while the background thread is doing the population).
Hope this helps.