Handling app termination during core data background population - iphone

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.

Related

Having complication data up to date when the user unlocks their watch?

I'm currently working on a simple app that displays data received over the network in a watchOS complication. Notably, this data is only relevant for ~30 minutes before a new network fetch is required.
I'd like to have the complication be up to date when the user unlocks their watch in the morning (this is a common use case presented by Apple).
Is it possible to receive some kind of background task when the user unlocks their watch? If I schedule a background task and the watch is locked and charging when the refresh happens, will the background task still fire? What techniques can I use to have data ready for the user when they wake up and unlock their watch? Is there documentation specifically focusing on background tasks when the watch is locked?
As far as I know, the watch works in its locked state only slightly differently from its unlock state.
One difference is the display of complications:
You can specify the privacy behaviour, i.e. what the clock face displays as complication (you can select what is displayed on the lock screen).
So, to my mind, it is possible to run background tasks as scheduled when the watch is locked and charging. Thus the data will automatically be ready when the watch is unlocked.
For this reason, there is no special documentation what happens when the watch is locked, except for some special cases, as what is displayed on the watch face in the locked state.
I would use the app life cycle docs here, and quite possibly choose:
in applicationDidEnterBackground(), I'd set a flag (time when the
complication was last updated). I'd suggest you use a singleton, so that it's accessible anywhere in your app.
then in applicationDidBecomeActive() i'd pick up the flag, compare it
with the current time, and notify the active ViewController to
refresh its data, if it's greater than 30 minutes.
if the flag doesn't exist, because the app was terminated, or it's a
first launch, then refresh anyway (set a 24h date in the past, to
use the same logic as in 1/,2/)
if you want to make it more permanent, use NSDefaults to store the last time the complication was updated.

Loaded Data and Multitasking?

I am writing a utility where data for games is written to disk at various stages throughout the game (including, but not relying on when the app exits). My question is currently I am doing my initial load using application:didFinishLaunchingWithOptions: but was curious about what happens when the application goes into the background / is suspended etc. Currently I am assuming that all my loaded data will hang around and I only need to do a load when the application initially loads. Is this the case or can iOS flush my stored data and I should look at checking if a load is needed in say applicationWillEnterForeground:
Also its a pretty small amount of data (20 small NSArray objects) but I guess I could always save and clear the data store when I get applicationDidEnterBackground: and reload on applicationWillEnterForeground: Or given that its just a small about of data would I be better to just leave it resident at all times?
Save your state when you get applicationWillResignActive:
That happens when you go into the background, or get a phone call, or several other interruptions occur. This is a better place than applicationDidEnterBackground: since that doesn't get called in devices running pre iOS 4.0 (which only matters if you support ios < 4).
Once your app goes into the background or is interrupted it can get killed without any warning, so this is your last sure chance to save/flush state data.
There is no need to reload data when you return to the foreground. If that happens, your app is still in memory with its data still there (except possibly view(s) may have been unloaded)
I advice that you always save your in-memory data when your app moves to the background. When in the background iOS may terminate your app when it needs the memory and you won't be notified when that happens.

applicationWillResignActive impact on application?

I am writing an application that records a users position at regular intervals whilst walking. I am using an NSTimers to schedule "startUpdatingLocation" followed by calling "stopUpdatingLocation" shortly afterwards to save as much battery as possible.
I want the user to be able to start the application and lock the phone thereby putting the application in an inactive state. My question is when this happens my application (when running via Xcode) seems to continue as normal, but I am curious if there are any differences in the way the application runs in this state as apposed to when the application is running as active?
From the docs it only mentions "applicationWillResignActive" with regards to the application passing through that state on its way to the background. I am more interested in how an application behaves when a used locks the UI and puts the phone away, I just want to make sure its going to keep doing what it should be doing or do I need to take extra measures?
When you app hits applicationWillResignActive it can continue to receive location updates if you use the UIBackgroundModes option in your apps info.plist.
Add the location key.
It is important that you do not use a timer in the background as timers will run but hold their "fire" until the app becomes active again. Thus you will only get one read when the user comes back to the app. The GPS location accuracy level is what will drive how much the battery is affected.
In your app description in the App Store, Apples requires:
Continued use of GPS running in the
background can dramatically decrease
battery life.
You app will not be allowed to go live until the above text is in the description for the user to read.
You should definitely be testing this on a device. The simulator doesn't auto-lock, for instance.
applicationWillResignActive is called when the user presses the home button, when another app fires a notification the user accepts (including when a call comes in), and when the device locks.
Look into the multitasking documentation, and what it has to say about background location updates.
My suggestion is that you conserve the user's battery by:
- starting a timer, which when fired, starts location updates (and stops the timer)
- when you get an adequately-accurate position record, stop location updates and restart the timer
- if location updates fail, restart the timer for a longer period. Maybe they're underground.
The most efficient approach is using significant location update service while your application is in the background or the screen is locked on your app. You might get one update every ten minutes or so.
Remember also, the user can disable your app's location services permissions. Especially these days...

iOS 4 Application Termination and Undo

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?)

How exactly does applicationWillTerminate work on iPhone?

I'm considering how to make my iPhone application as "bullet proof" as possible.
Right now, I'm thinking about how the app will respond to the user hitting the home button at a critical point in the application's processing.
What exactly happens? Are any more instructions executed in the application's threads?
When applicationWillTerminate gets called, I've read that the application "has a few seconds before the os kills the process" - again, what exactly happens?
What I've observed is that the home screen appears immediately, but the app is allowed to continue running in the background for at least a few seconds. If it takes too long, it will get killed.
applicationWillTerminate is called when your application exits due to a call a user decides to take or when the OS kills it due to some other reason. You cannot stop the app from being terminated but can store some data which you want to use later in this method.
For instance if your app lets the user search for something, you can save the search term when the app is about to terminate (in applicationWillTerminate) method so you can use it later when the user logs in to the app again.
So the implementation of the method depends on what you want your app to do when the user decides to quit the app or the OS kills it.
I hear you get about 4.8 seconds to do processing from when applicationWillTerminate gets called otherwise it gets killed. Basically save anything you need quickly!