Multitasking in iOS
It might not be a bigger feature in iOS 4 than multitasking, so let’s review it, and most importantly, how to enable multitasking on our apps.
As we all know, Apple was reluctant to let third party apps to run in the background. Mobile devices, Apple maintains, have limited resources (CPU, RAM, etc), and thus, there is no a lot of room for general purpose concurrency. On the other hand, the vast majority of apps just don’t need to be running on the background to make life easier. They just need to be preserved between runs. And that’s the very essence of the multitasking implementation of iOS, preserve the state of all applications to enable fast switches, and give access to a more sophisticated concurrent system for the apps that really needs this kind of service. So, before jumping to the nuts and volts, let’s review the life cycle of an application.
Life Cycle
in iPhone OS 3.x we found three very distinctive states:
- Active: The app is in the foreground. The user can interact directly with the app.
- Inactive: The app is still loaded into memory, but the system has stopped it to show, let’s say, an SMS or any other warning. The user can either dismiss the alert and get back to the app, in this case the app will resume its active state, or it can kill the app.
- Not running: which leads the app to a third state, the not running state.
iOS app life cycle is mostly the same, with the addition of two new background states:
- Running: As we have discussed, there are some applications that need keep running on the background.
- Suspended: This is the sate that most of the apps will end when in background. The system tries to minimize the impact of any given app on the entire system. The application is not terminated, and hence it is a lot easier to bring it back to foreground if needed.
Unlike iPhone OS 3.x, when the user hits the home button, the app in the foreground is not terminated. It will first become a running background process, and later it will become a suspended app. The system will kill the app just if it need to reclaim memory, or the app is not behaving (see below).
Different flavours
With iOS 4 we have a number of technologies to enhance the user experience.
- Fast App Switching: the idea is to give users a better experience reducing the times that the app needs to be loaded.
- Push Notifications: With APNS we can let server do the heavy lifting, and let the user know when some important thing appears on the horizon.
- Local Notifications: Let’s say you just need to wake your app after a given amount of time elapses, local notifications can help you here.
- Background audio: Play audible content even if the app is not the foreground process.
- Task Completion: The user just tap the home button, but your app is not done retrieving some important piece of data from the network? Now you can let the OS that you need a few more extra time to get your job done.
- Navigation: Keep users informed about their location via GPS.
- Significant Location Changes: For most location aware applications, there is really no need for a GPS grade accuracy. If you just need to know when the user enters or exit a given region, then this is a wonderful set of APIs with a low impact on resources (they are almost free. And if there is another app running GPS, you get the GPS data for free).
- Voice over IP. This is the kind of technology that really needs to be concurrent.
Fast Switching is enabled by default in iOS 4. You only need to register the app if you need background audio, location or VoIP, you have to set UIBackgroundModes appropriately in the app’s info.plist
<key>UIBackgroundModes</key>
<array>
<string>audio</string>
<string>location</string>
<string>voip</string>
</array>
Situation awareness
So, how we can know the status of out application? Well, Apple introduced a few new methods to the UIApplicationDelegate protocol.
– applicationDidEnterBackground:
– applicationWillEnterForeground:
By the way, do yourself a favor, and never ever use – applicationDidFinishLaunching: again, and use – application:didFinishLaunchingWithOptions: instead. Even if you are not using APNS, it is better to be prepared.
Remember that when the system boots your application, your delegate will receive – application:didFinishLaunchingWithOptions: (or – applicationDidFinishLaunching: if you insist). A moment later, the delegate will be notified that the app is now active and in the foreground with a call to – applicationDidBecomeActive: (and will receive a call to – applicationWillResignActive: when the app needs to relinquish the active state in response to an alert, a phone call or any other system activity).
The call to – applicationDidEnterBackground: informs our application that the system is moving it from the foreground to the background. Here is where we have to save the application state, try to reduce memory usage and any other thing that might have a negative impact on the rest of the system. As we have said, the system will first configure the app as a running background app. Depending on the kind of services the app benefits from, the system might keep the app as a running background process, or change yet one more time its status to suspended. Unfortunately, the system will not notify this change to the app.
When the app is about to enter background, we need to accomplish a few task:
- Save App State: We need to preserve the state of the app to let the user resume his or her activity as soon as the app gets back to foreground.
- Reduce Memory Usage: The system will terminate your app if it does not behave. Memory is always a scarce resource, don’t play with it. When in need, the system will start terminating the suspended apps that uses more memory, and then the running background apps that uses a large chunk of memory.
- Prepare UI: The system will take an screenshot just before the app goes into background (to show later when the app is about to enters back into foreground), so, stop any animation, hide any sensitive information and comb your self :)
- Stop Bonjour: listening to network services is really expensive, and besides, if your application get suspended, it will not be able to respond to network messages. So close any socket and any other network service. Use APNS instead.
- Stop OpenGL. GPU is strictly off limits for background processes. You can’t create EAGLContext or issue any OpenGL command. Offending apps are going to be terminated by the system.
- Relinquish exclusive access to calendars, media libraries, address book, or any other shared data. Again, the system enforces this policy killing any application that, when in background, tries to retain exclusive access to some shared system data.
Now, the user selects again the app in the Spring Board, and the system needs to get it back to the foreground. If the application was suspended by the system, it will be first get back to the running background state, again with no notification at all. Once in the running state, it will receive a call to – applicationWillEnterForeground: just before it gains foreground status as an inactive process, and then the all familiar – applicationDidBecomeActive:.
And, you might also find interesting that, for each call to the UIApplicationDelegate there is a notification also posted:
UIApplicationDelegate message |
Notification |
|---|---|
– applicationDidBecomeActive: |
UIApplicationDidBecomeActiveNotification |
– applicationDidEnterBackground: |
UIApplicationDidEnterBackgroundNotification |
– application:didFinishLaunchingWithOptions: |
UIApplicationDidFinishLaunchingNotification |
– applicationWilEnterForegound: |
UIApplicationWillEnterForegroundNotification |
– applicationWillResignActive: |
UIApplicationWillResignActiveNotification |
– applicationWillTerminate: |
UIApplicationWillTerminateNotification |
Waking Up
In the period of time since the app goes background, and is restored to foreground, many things can happens. Network can change, the user can flip the locale, etc. Since the application is suspended, it will not receive any notification, but the system will keep record of all these changes, and when the app resumes, it will deliver all the notifications. In other words, be prepared to handle the burst.
If your app is network dependent, the most important change might be the lost of accessibility. Don’t assume that if you were able to reach your source before goes to background, you will be able later.