Loaded Data and Multitasking? - iphone

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.

Related

How to avoid my app to be terminated, when it's running and tracking my location in the background?

I am making an app, which needs to keep tracking user's location every time. It can also work in the background mode. The issue is When I use other apps for several times. The other app may cause lots of memory. My app sometimes be terminated by the system. There are no crash logs. So I want to know some reasons. Is there any way to avoid my app to be terminated? Very appreciate for your help.
You can't prevent the app the be terminated, but what can you do best to keep it alive is when it enters in background free as much memory as you can - cached images, files... Also stop any running timers, UI updates and everything time consuming. By following the MVC rules, the best implementation is to create a separate class (model) that's only responsible for location updates (with CLLocationManager inside, and the class implements its delegation methods). So the only thing in background you should do is collecting the location points received by the CLLocationManager and nothing else. Also implement the method -applicationWillTerminate in you AppDelegate. This method is called only when the app is in background and it's going to be terminated (either by the OS or the user) and inside persist the location points in CoreData for example or however you do it... I have such an approach and so far my app has lived for 24h (with charging of course) without being killed.
App running in the background depend upon memory usage, battery life etc.When there are many app running in the background, your app may get terminated.I do not think you can run your app permanently in background.

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.

Managing Memory in App When Running in Background - correct Procedure?

I've just been reading this post on notifications being sent to apps running in the background :
Not getting didReceiveMemoryWarning when app is in the background
My question is that since an app in the background will not act on a didRecieveMemoryWarning until it enters the foreground again, what is the recommended way to free up memory in your app if it is running in the background when the memory notification is sent - or is this not possible ?
In iOS 4.0 and later, - (void)applicationDidEnterBackground:(UIApplication *)application method is called instead of the applicationWillTerminate: method when the user quits an application that supports background execution.
You should use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
You should also disable updates to your application’s user interface and avoid using some types of shared system resources (such as the user’s contacts database). It is also imperative that you avoid using OpenGL ES in the background.
Your implementation of this method has approximately five seconds to perform any tasks and return. If you need additional time to perform any final tasks, you can request additional execution time from the system by calling beginBackgroundTaskWithExpirationHandler:. In practice, you should return from applicationDidEnterBackground: as quickly as possible. If the method does not return before time runs out your application is terminated and purged from memory.
If your app is running in the background (because it is, for example, a Voice over IP app that is allowed to run in the background), it will receive memory warning notifications in the same way as if it were running in the foreground, and you should deal with them accordingly.
However, if your app is suspended in the background, it won't receive memory warnings or other notifications. Your job is to free as much memory as possible before your app enters the background. Once you're in the background, you have no way to do anything anymore. The OS will decide whether to kill your app or not (without notifying you again) at its discretion.

iOS: Prevent a background location service from getting unloaded when the system sends a low memory warning

I've got a location service running in the background, but I'm finding that sometimes if the user runs a number of other apps in the foreground my app will get unloaded.
Using Instruments my app currently consumes about 1.2MB in the background. A project with an empty view consumes about 600KB in the background. I know I have some improvements that can be made to bring this closer to the minimum, but beyond that is there anything else I can do to prevent my app from getting unloaded? Since my app is actually doing something "useful" in the background, is there a way to indicate this to the system so that my app will get preference some other suspended app like a game which doesn't need that memory?
Does anyone know how the algorithm works in terms of which background apps are flushed first? Is it by order of memory usage, by oldest open app in the foreground, by oldest run thread in the background?
To expand on the question:
What are the right trade-offs to be made in this service scenario? I can move my CLLocation into the AppDelegate. Should I force my ViewController to unload every time it enters into the background, such that my background memory usage is the absolute minimum, but trading off start-up time and forcing a reload of cached map tiles? Or can I wait until I get the didReceiveMemoryWarning before releasing the viewController?
If I had some sense of the order in which apps will be killed that would help to make the right trade-offs. For instance is there a round robin approach where the oldest suspended app gets the warning first. Then on coming around again if the system still needs more memory it does the actually killing? Or does the system issue the memory warning to an app, sees that not enough has been freed and than kills the app, then moves onto the next suspended app. Or is the order by memory usage?
Any best practices in on this subject would be appreciated.
Update:
After spending half a day converting my app from ARC & Storyboard back to to manual allocation, I still found that the background memory usage was roughly the same. Even though I removed all view controllers from the view and released them, the system still doesn't free that memory immediately. So in the end my app was just as likely to be killed as it was when I was using ARC. What's more interesting is that my app never gets a didRecieveMemoryWarning and my viewDidUnload never gets called, my app just gets killed without notification.
Luckily it was pointed out to me in the Apple Developer forum that if MonitoringSignificantLocationChanges is enabled even if my app is killed it will get reloaded on a significant location change.
I just had to be cognizant that my app could be re-launched from the background and had to use [[UIApplication sharedApplication] applicationState] to handle that event accordingly.
Well you can't stop iOS from killing your app, that's just the way the system works.
If there is a memory low memory warning iOS will kill the some of the apps that are running in the background.
Tips are just keep your memory usage as low as posible.

How to tell if iPhone application was launched by backgrounding or not

My application uses NSUserDefaults to store some values so that it can restore them on application update or if backgrounding is quit. Backgrounding automatically saves my integer values, but if the user quits the application from the launcher, the numbers are lost too, and the ViewDidUnload method I guess doesn't evoke when entering backgrounding. Is there a way that I can save the NSUserDefaults any time the application unloads. Also, the ViewDidLoad method had the same problem, it doesn't evoke from backgrounding. What's a way around this?
P.S. So far the only data my application needs to save is an int for an on-screen count.
UPDATE: UIApplicationDidEnterBackgroundingNotification works great with your suggestions!
You can't save data right before it eventually gets killed, but you can save state 'just in case' in your applicationDidEnterBackground: app delegate.
There's also applicationDidBecomeActive:, but there's no reason to load your save data from there, since when it's invoked from an app that was in the background, the data will have been preserved any way.
You can't tell if your app was launched from the background or not, at least how it's currently set up, since your app delegate will get the same sequence of events if it's launched from springboard.
As Joost says, you should save anything you need to restore state inside the applicationDidEnterBackground callback; essentially, you should assume this is the last message your app will get before it gets killed mercilessly by an evil process reaper.
You should check out the WWDC 2010 Session Videos, specifically, Session 105 - Adopting Multitasking on iPhone OS, Part 1 for a thorough explanation.