UPDATE: Added handleOpenURL to the flow charts. Added UIApplicationExitsOnSuspend. Untangled some lines.
UPDATE: renamed deprecated handleOpenURL to newer name.
Now that we all are moving our source code gradually to iOS 4 I had to pause and think a bit about where to move which code. A problem that I’m facing frequently when updating a project is that the didFinishLaunching is only called if the app really launches.
That poses a bit of a challenge if you are used to doing things like refreshing images or other files off the internet. An app that is resumed from standby does no longer go through this delegate method. So an app that would always show fresh content upon launch before 4.0 multitasking would no longer load any new content as soon as you build it for 4.0. That’s actually one of the main reasons why I have not yet had time to update MyAppSales to 4.0.
To gain the possibility for “fast app switching” you actually don’t need to do anything. All apps automatically support it because they no longer get terminated if the user pushes the Home button. They get put into a sleep mode while the iPhone still has enough memory for everything else. It’s only if RAM runs out that the OS starts killing apps. There is begins with the ones that have the most memory reserved.
I grabbed the free trial of Omnigraffle and the Non-techie Process Flowchart Stencils by gfraser. Then I researched when all these various delegate methods of UIApplication are being called and drew charts to illustrate the flow.
By inhaling first how it was before multitasking and then upgrading your mental process to backgrounding we can begin to fully appreciate how it all fits together.
The World Before Multitasking
The first thing that I learned from this is that applicationDidBecomeActive: is being called right after application:didFinishLaunchingWithOptions:. So even before 4.0 it would have been smart to put there any kind of code that you want executed whenever the app becomes active, be it after app start or upon rejecting a phone call.
Not shown on this diagram is the situation that your app is eating up all the system memory and ignores both the level 1 and level 2 memory warnings. In that case the OS will also terminate your app without totally unscrupulous.
The mechanism with WillResignActive and DidBecomeActive is sort of the Backgrounding Lite that has always been there. This occurs whenever some other thing is displayed in front of your app. This could be the UI to accept a phone call or something as benign as the synching screen.
Multitasking ON
Adding multitasking to this flow chart makes it about twice as complex. I probably spent an hour trying to fit it all together with no crossing lines. Another thing that I noticed while doing this is that applicationWillResignActive: is the only delegate method that I could not optimize into a single box, because one use is to show that the app has been interrupted, the other is to the path into the background.
An app built with 3.2 will still go through a short background stage where applicationDidEnterBackground: is called. but then it will be terminated as usual. If the same app is built against a 4.x SDK then it will not go straight from background to being terminated. Instead it will stick around and so will be the debugger. As soon as you tap the app icon again or choose it from the app switcher it is first informed that applicationWillEnterForeground and then applicationDidBecomeActive.
An app that is suspended but still in RAM might be terminated by the OS if memory runs low. But after entering the background there is no longer any delegate method being called, instead the app will receive a KILL signal. This occurs also if the user long-presses the app icon in app switcher and then removes the app from there with the removal button.
Accepting a phone call no longer terminates your app but will send it into the appropriate background mode. Within the background box you see two purple states that the app can be in. All apps are suspended in RAM per default. You might want to slim down your memory footprint to make your app a less likely target for killing if the system runs low on memory.
Only apps that actually require background processing continue to be executing. This requirement is either set in info.plist or by telling the OS that you have a task to complete, like for example a file upload.
The following kinds of activities get to run in true multi tasking behind the foreground app with lesser CPU priority.
- playing music: “App plays audio”
- geo location: “App registers for location updates”
- VOIP: “App provides Voice over IP services”
If your app does one of these things then adding the key to info.plist is all it takes. But be aware that as soon as your app stops doing what it stated it would be doing the OS again will send it to sleep, only to be awakend by another gentle tap by the user.
In background mode you’re advised to stop updating the UI. Especially with OpenGL Apple is really strict. If you app as much as touches OpenGL while in background the app gets killed right away.
There are only two scenarios left where your app’s applicationWillTerminate: will actually be called: if it’s build with an SDK of less than version 4.0 or if you chose to opt out of backgrounding by adding the UIApplicationExitsOnSuspend key to your info.plist.
So, let’s ask the question we’ve been doing all this fuss for: Where should you now put your code to initialize, update or save changes? applicationWillTerminate not being called in the majority of cases makes it a rather bad candidate to save user defaults or data.
Looking at the chart I see applicationDidEnterBackground as the ideal candidate delegate method for saving state. This is also the last method to be called before a regular 4.0 app gets put to sleep and before a possible kill.
For updating data from the web the case is not as clear. You would not want to reload every time the user comes back to your app. Possible applicationDidBecomeActive: is a good place, provided that you only reload data if sufficient time has passed to be able to assume that something new is available.
Only the first loading of data can stay in application:didFinishLaunchingWithOptions: since every call applicationDidBecomeActive: most likely has the data already loaded previously.
Conclusion
Adding fast app switching and multitasking support is quite easy since for the most part you don’t need to do anything. But you WILL have to review the contents of your app delegate methods to see which code has to be moved into one of the other delegate methods now. Clean out applicationWillTerminate: and have a close look at application:didFinishLaunchingWithOptions: to check if you have something in there that needs to be done every time the app becomes active.
These charts come from some experimentation that I did and what I remembered from the WWDC 2010 session videos on multitasking. Potentially there are mistakes or more surprises hidden in there. Please let me know if you find any.
Here’s the chart in PDF format in case you want to print it out and frame it.
Categories: Recipes
Thanks for creating the flowcharts! I will certainly come back to them the next time I need to quickly get an overview of all application delegate messages.
Thanks! You should make sure, if you downloaded the PDF, to get the latest version. What you don’t see here is the amount of times where I found an unnecessary corner in a connector or something else that’s wrong. I think I made a dozen mods so far. What a waste of time. 😉
This is a great chart, thanks!
excellent chart! thank you. i’m about to add fast app-switching support to an app & i’d just finished watching the multitasking WWDC video. i’ll be referring to this article a lot.
one question: on devices that are running iOS4 but do not support multitasking (iPhone 3G, iPod touch 2nd gen), what does the flowchart look like? my guess is that it would behave as though UIApplicationExitsOnSuspend was set. if so, then that’s another scenario when applicationWillTerminate: will be called, right?
Then the first chart applies, that’s why it’s still there. I found though that even a 3.2 app would get it’s didEnterBackground called but would then terminate. That’s why I have this decider “SDK >= 4”.
i see. please bear with me so i make sure i understand this exactly 🙂 if i have an app built with a base SDK of iOS 4, running on an iPhone 3G running iOS 4, then when the user hits the home button, my app does *not* receive applicationWillResignActive: nor applicationWillEnterBackground: before receiving applicationWillTerminate:?
thanks again for the article and the charts.
I just did a quick test with iOS4 on my iPhone 3G, with a simple app built with iPhone SDK 4. When the user presses the Home button, the app *does* receive applicationWillResignActive: and applicationDidEnterBackground:, right before applicationWillTerminate: is called. Thus the first chart is *not* in effect with an iOS4 app on an iOS4 device without multitasking. For completeness, you might want to add another decision box to the second chart ( “if iPhone 3G or iPod touch 2nd Gen” -> “applicationWillTerminate:” ).
Sorry, correction: if user presses home button, the app does NOT get applicationWillResignActive: but DOES get applicationDidEnterBackground:, followed by applicationWillTerminate:.
This is actually also the case when UIApplicationExitsOnSuspend is set: pressing the home button does NOT call applicationWillResignActive: on the delegate before applicationDidEnterBackground: and applicationWillTerminate:.
This is complicated!
Drops,
Thank you SO much for taking the time to document this so clearly, and then sharing it. I can’t tell you how often I’ve referred to your diagram over the last few months. I do have one suggestion — there is a transition from “App suspended in RAM” to “App Ended” that corresponds to the “force close” user activity of
1. Hitting the home button to background the app
2. Bringing up the list of backgrounded apps (by double clicking home)
3. Touching the apps until they start jiggling.
4. Deleting the backgrounded app.
This transition caused me some grief until I understood what was happening, because it occurs without any events being passed to the suspended app. This is especially troublesome for apps that do a lot of database reading/writing. If the app is suspended during db processing, and then the app is “force closed” without the database being closed, then most often the sqlite engine will flag the db as being corrupt on all future attempts to access it. A Very Bad Thing indeed.
T.
Hi,
I want to know what tool you use to create the chart.
Should you give me the tool name?
Thanks!
Omnigraffle Demo plus a Stencil pack I found
hi Drops!
is there any option to enable multitasking only for iPhone in an Universal app? I dont want my app to run in background in iPad.
Depends on what kind of multitasking you are referring to. The only way how you could achieve the app exiting in iPad would be to do exit(0) to quit it.
heartfelt thanks Drops.! Will try it out.
Very helpful. Thanks!
I’m curious about this:
“This requirement is either set in info.plist or by telling the OS that you have a task to complete, like for example a file upload.”
How do you inform the OS that you have an on-going task that needs to complete?
For each application, there are two modes : foreground and background , there is no 3rd , right ?
So if correct, I want to know which mode applicationWillTerminate: run ? From the chart, seem like it is in Foreground, but if so, if user pick up telephone, the app will go to background first, then check SDK >= 4, if answer is No, it will go to applicationWillTerminate: (in foreground mode ) .
Welcome further talk with apple.dev.sh(at)gmail.com
Thanks
I don’t understand where you’re going with your question.
Thank you for your clear explanations and diagrams. This is the best description of iOS backgrounding that I’ve found!
Thanks a lot for your great work. I imagine it was hard to make a readable schema. It’ll help me!
Hi,
your flowchart is missing one more connection – from (Background Run Loop) to [applicationWillTerminate].
While this usually does NOT happen, it might when iOS desperately needs resources for the front application.
See:
https://devforums.apple.com/message/433968#433968
Hi Drops,
Good article and well written. This is very helpful understanding the complete flow.
Thanks.
This is fabulous work!!
Been working on some iOS5 changes, and a few notes:
Lock screen iOS5
– resignActive -> didEnterBackground
Lock Screen iOS4
– resignActive
Notification Center Slide down / Slide Up
– resignActive / becomeActive
@KingOfBrian
Nice diagram BUT it does not depict launch-into-background like one sees in Newsstand.
For IAP (In App Purchase) it does this:
Foreground Run Loop
Interruption (Want to buy an IAP)
applicationWillResignActive
You are now being asked by App Store to confirm your IAP purchase
applicationDidBecomeActive
Foreground Run Loop
Notice that it does NOT do applicationDidEnterBackground (whether you buy an IAP or not).
Its always applicationWillResignActive > applicationDidBecomeActive everytime.
This can actually occur 2 or 3 times during the IAP process.
More info
http://stackoverflow.com/questions/9424302/how-to-know-that-skstorekit-in-app-purchses-caused-applicationwillresignactive
Awesome chart, thanks. Juste one question though: what will happen if you leave your application on the foreground and don’t touch your device. Will the application resign active after some time ?
There is a time out timer that will darken the screen and after a while lock the screen if the user has this enabled. The latter will resign active. Generally resign active means that the app is no longer visible.
this was really very helpful
any chance of releasing another one for iOS 8. There are a lot of new situations involving push notifications and background tasks that do unexpected things
occhiali da sole oakley scontati polarizzati ruby irid polar
In fact no matter if someone doesn’t be aware of afterward its up to other visitors that they will
assist, so here it happens.