Adding iOS4 Multitasking SupportJul 4, 2010 · 7 minute read
After updating the images in your app to take advantage of the higher resolution iPhone 4 retinal display the next thing you should really thing about doing is adding support for multitasking. There are several related features that you may choose to include each requiring different levels of effort to implement:
- Fast App Switching
- Local Notifications
- Task Completion (extra time to complete a task in the background)
In this post I am going to focus on adding support for Fast App Switching which is pretty much mandatory for any well behaved iOS 4 application. Fast App Switching is what allows your app to move between the foreground and background using the home button and the scrollable list of recently used apps.
Building with the iOS 4 SDK
The good news is that if you do nothing to your app but rebuild it with the iOS 4 SDK you will, by default, enable support for fast app switching. If for some reason you do not want an application to support background operations you must add the UIApplicationExistsOnSuspend key to the Info.plist file for that target (and set the value to YES):
Rebuilding your app is an easy first step but it often not sufficient to make your app behave well when it is being switched between the foreground and background. To understand why it is worth understanding the different states that an iOS 4 application can be in and how it moves between them. When an application is launched and during its life it can move back and forth between the background and foreground.
An application in the foreground is visible to the user and can be in either the active state where it is running and receiving events or the inactive state where it is running but not receiving events (for example when the user has been prompted to answer an incoming call).
An application in the background is normally not directly visible to the user and can be in either a suspended state or a running state. A suspended background application is effectively frozen and does nothing until woken or terminated by the system. An application running in the background has some more options to interact with certain Apple approved API’s for VOIP, audio or location services. This background running state is also where an application will be when it has asked for more time to complete a task in the background (such as downloading a file).
As the application moves between these states a number of methods are called in the application delegate to give you the chance to react correctly. Your application will most likely need to implement one or more of these to function correctly:
For each of the delegate methods there is also a corresponding notification which is useful if you want a view controller to take some specific actions. Setup the view controller to observe the notification and if it is running when the state transition happens it will get a call back.
Moving to the background
When a user “quits” an application by pressing the home button a multitasking enabled App will actually move to the background instead of terminating. The application delegate method applicationWillResignActive will be called first to give you a chance to pause any ongoing tasks and then as the application moves to the background applicationDidEnterBackground will be called.
It can be confusing to know what to place in which of these two delegate methods. The applicationWillResignActive method indicates that your application is about to enter the foreground inactive state. This can happen either because the user has quit the application, it is moving towards the background or because of a temporary interruption such as incoming call or SMS. It is possible that the user will choose to ignore the call and your application will then return to the foreground active state. So typically you want to pause any ongoing activities in this state but not cancel or cleanup things that may shortly need to resume.
Once applicationDidEnterBackground is called you can be sure that you moving to the background so you should do what you need to do to save the application state, reduce memory usage and release any shared resources. You have about five seconds to get this done before the system suspends the app.
It is important to understand that applicationDidEnterBackground replaces the call to applicationWillTerminate for multi-tasking aware applications. An iOS multitasking application will generally never have its applicationWillTerminate method called because it is never usually terminated.
When a user hits the home button the application moves to the background where it may continue to run or be suspended. A user can force quit an application by touching and holding the application icons in the scrollable list of recently used Apps and then touching the red “-” badge on the application icon. In this situation the application is sent a SIGKILL and exits immediately without ever calling applicationWillTerminate. You have no way to intercept this situation and perform additional actions so you should make sure you do what you need to do in applicationDidEnterBackground.
There is one situation where applicationWillTerminate is still called. Applications that actually continue to run in the background because they have requested extra time or access to the background VOIP, audio or location services can be terminated by the system and will receive a call to applicationWillTerminate.
When adding support for fast app switching you should consider the following common actions (not all will apply to all applications):
Saving Application State
As already mentioned when your application enters the background state (applicationDidEnterBackground) it should immediately save its state so that if it is terminated everything can be restored. It is hard to provide examples of this as it is very application specific. Remember though that you only have about five seconds to get everything done (the same limitation that previously applied to doing any work in applicationWillTerminate).
If you need more time you should investigate completing long running tasks in the background using beginBackgroundTaskWithExpirationHandler.
Reducing Memory Usage
The system will terminate background apps when it is running low on memory. First on the list of apps that will be terminated are suspended background apps that are using a high amount of memory (Apple has not as far as I know stated what “high” means). Next in order are high memory consuming apps running in the background. So the more memory you use in the background the more likely is it that the system will kill the app when it needs memory.
To increase your apps chances of survival you should try to reduce memory usage when moving to the background. The system will take care of things like releasing non-visible view controllers, image and core data caches. The app should release any other application specific caches or resources. One word of caution though, since the idea is to allow the user to quickly switch between apps you do not want to be freeing resources that will slow up the app when it moves back to the foreground.
As mention previously you should pause any long running activities in applicationDidResignActive. Apple also suggests that you dismiss any alerts or action sheets you may be displaying since your app could be suspended for some time. The question to ask is will the user still understand the alert message if they resume the app several days later?
If you have several different view controllers that could potentially be displaying an alert or action sheet you may find it easier to register them individually for the UIApplicationWillResignActiveNotification.
Close Network Sockets
If you have any open network sockets (or Bonjour operations) you should close them in applicationDidEnterBackground. You can reopen them in applicationWillEnterForeground.
Release Shared System Resources
If you access the system calendar, address book or music libraries you should release them in applicationDidEnterBackground. If you fail to do so the system will terminate the app once it is suspended. If your app is unexpectedly quitting when it moves to the background it may well be because you have forgotten to release a shared resource.
This has been a long, descriptive post without any code examples. That is partly because the actual code is very app specific but also because in many cases there is very little new code you need to write to support fast app switching. In most cases you can get by by rebuilding with iOS 4 and moving a small amount of code that you most probably already have in applicationWillTerminate into applicationWillEnterBackground.