Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2011-320
$eventId
ID of event: wwdc2011
$eventContentId
ID of session without event part: 320
$eventShortId
Shortened ID of event: wwdc11
$year
Year of session: 2011
$extension
Extension of original filename: mp4
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: [2011] [Session 320] Adopting Mu...

WWDC11 • Session 320

Adopting Multitasking in Your App

Developer Tools • iOS • 55:00

If your app would benefit from playing audio or updating location when in the background, or completing a task even after the user leaves, or from fast app switching, you will want to learn about multitasking in iOS. A must attend session if you plan to use multitasking in your app.

Speakers: Dave Myszewski, Charles Srisuwananukorn

Unlisted on Apple Developer site

Downloads from Apple

SD Video (98.3 MB)

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good afternoon. Welcome to the talk on multitasking this year. I'm Dave Myszewski. I manage an iOS performance team and I'll be joined by my colleague, Charles Srisuwananukorn. So today we're going to tell you about multitasking. So, and in particular, so multitasking, as you know, provides a lot of great services to enable your application to run in the background when it needs to and to ensure that applications don't run in the background when they don't need to.

So when your application goes to the background, they're suspended and not running, which means that we have really great performance because you don't have a lot of things going on in the background that are using, you know, you don't have 50 things using 1% of the CPU and a bad user experience. And it's also been really terrific for battery life. So applications run when they need to and don't run when they don't need to.

Multitasking is supported on all iOS devices today. So the iPad, iPad 2, all versions of the iPhone that iOS 5 supports, and the iPod Touch as well. So in 4.2, everything supports it. And today we're not going to tell you a whole lot about particular APIs. We're going to focus our session today on how to make a really great multitasking app.

So we had a couple of talks last year that if you want to review on iTunes after the show, you can do that. But today we're going to focus on how you make your application really optimized for multitasking. And we have a few different ways in which we'll talk about making your application really great. So to start out, we'll review the application lifecycle, and then talk about making that great application that's in the background. And then talk a little bit about the multitasking services, including the new services in iOS 5.

So we'll start out with the application lifecycle. Things work by and large like they did with iOS 4, except with one change that we'll get to in a moment. But when you're sitting here on the home screen and your user launches the app, of course the application isn't running. You will get, when the application comes to the foreground, an application did finish launching with options delegate, and then the application becomes active.

So that's the lifecycle that you're all used to and has been the same since 2.0. Then when you have some sort of interruption, which will become a lot less common in iOS 5 because of our new notification center, but it still happens in, say, the multitasking UI, your application will get the application will resign active callback. So something's interrupting your application, and your application knows to maybe stop playing that game or to perhaps change its UI.

And then when you change from your application, you'll start out as the active app. Your application goes into the background because you hit the home button. To get there, the application, you'll get an application did resign active callback. And then your application goes into the background and runs for some amount of time.

So this is when you will want to do things like save your state and clean up things in your application to prepare it to go into the background. So you'll get an application did enter background callback. And then once you're done with that, Springboard will suspend the application. Now, you don't get a notification that tells you you're suspended. Just presume that when you finish with the application did enter background that your application is finished doing everything that it needs to do when it goes into the background. So there's no notification here.

Then switching to an app is very symmetric. When you're suspended, the user launches your app either through the app switcher or the home screen. You'll get the app--again, no notification that you started running. And the moment you start running, you'll get an application will enter foreground delegate callback. And then, of course, your application will become active. So that's the same basic lifecycle for an application. And that's the same as what it was in iOS 4.

Now in iOS 5, we're doing one thing a little bit differently, and that's we're handling the device lock differently. So what we found with iOS 4 is that if you lock over the device, the application continued running while the device is locked. Now iOS, you know, even when the screen is off, is a fairly dynamic system.

It will wake up periodically to handle things like push notifications that happen, or if you have a region monitoring with, say, the new Reminders UI that allows you to do location-based reminders, or some other third-party application that does a similar thing, then the application--then the device will wake up and do some amount of work with the screen is off.

And as an application, you don't necessarily know how to distinguish that lock screen where in the past you would get an application did resign active, or application will resign active, from your application really being idle. So what we had is that some application might talk to the network inadvertently or enable the GPS, and things like that had an impact on battery life. So what we did now is when you touch that lock screen button, you'll get the application will resign active like before, but now your application will enter the background.

And then when the user hits the home button, the application will say suspended. So we won't change from that suspended state until the user unlocks the device and goes to your application. So that's one thing that's different in iOS 5. iOS 5 than iOS 4, and it helps improve our battery life.

Now of course for all of these app lifecycle notifications, or delegate callbacks rather, there's a corresponding notification. These are all unchanged from iOS 5. So for your application did enter background, for example, you may have some cache that's very well divorced from your UI application delegate. And for something like that where you want to clear a cache, you can use the UI application did enter background notification.

And there's a few other ways that you can handle caches that we'll get to a little bit later in the talk. Now that covers the case where you go into the background and you don't continue running. But of course we provide various facilities for you to continue running into the background. So you can finish the current task that you're in the middle of. You can finish playing audio, for example, until the user pauses you. We provide some external triggers for you to run on.

So things like location notifications and newsstand is another one that will allow you to download some content in the background if you're a magazine user. So you can run in the background if you're a magazine developer or newspaper. And we have in VoIP apps some targeted networking events that wake up the devices.

So that's kind of three general ways in which you run in the background. The most common one, though, is what we call task completion. And that merely lets you finish doing whatever it was that the user was doing in the foreground. So you might finish uploading photos, for example.

So when the user is switched away from their app, they press the home button. Then you're in that background running state. But rather than being suspended, you continue finishing those photos. And then once you've uploaded the photos, then your upload is completed. You declare that you're done. And then your application is suspended.

And background audio works very much the same way in that the user is playing audio in the foreground, then the user presses the home button, and you continue playing audio until the user declares that they're done by pausing the music, or maybe you get an interruption, like a phone call.

And then the application is suspended. So all of our multitasking modes, whether it's audio or location or task completion, provide mechanisms like this that let you keep doing what you were doing until you're done with the task at hand, or until the user declares that they're done, like they're done playing audio.

[Transcript missing]

So first I'm going to start with system resources and talk about how iOS manages system resources and tries to mediate access to these resources. Some of the APIs that you may not be familiar with that would help you manage these resources and some other things that your app can do to help manage resources. And in particular I'm going to focus on a couple of particularly tricky areas, and specifically memory and OpenGL.

And then after that Dave's going to come back and tell us more about gracefully resuming from the background. So let's talk about system resources. The way to think about system resources is that all the system resources on a device are shared by all applications. Like foreground applications and background applications all share these really limited resources. And so the more resources you use, the fewer resources are left for other people. So just as if you're sharing a birthday cake or something, the more birthday cake you have, the less there is for everybody else.

And so to keep everybody happy, you want to make sure everybody has a birthday cake. And so the last thing you want to be is that kid who eats all the cake and doesn't leave anything for anybody else. So again, all applications on the device, foreground, background, system applications, share system resources. And this includes resources that you may already be familiar with, like CPU and IO. There's a limited amount of bandwidth to flash. And so you have to share that bandwidth among the different applications.

And memory. But it also includes some of the other things that you might want to be aware of. So again, there's some resources that you may not have thought of, like the GPU and network. So again, especially on these devices over the cellular network, there's a very limited amount of bandwidth that needs to be shared among different applications.

Now, iOS will prioritize some of these resources for the foreground app. So when your application is in the foreground and, say, it wants some time on the CPU, at the same time that a background application wants some time on the CPU, iOS will actually prioritize your application higher and give your app time on the CPU.

Similarly, with I/O, if your app wants to do I/O while a background application wants to do I/O, the foreground application wins. Now, there are also some resources that are just really difficult to manage, and so they're just completely off limits while your application is in the background, and in particular, the GPU.

So if your application tries to use OpenGL while it's running in the background, the system can't efficiently manage that between the foreground and background applications, and so it'll terminate your application. So this is something to keep in mind. And other resources, specifically memory, the system does try to manage as best as it can, but there's a lot that your application can do to help the system manage memory. Some APIs that it could use, and also just freeing up memory so that when your application is suspended in the background, there's more memory for other apps on the system to use.

And so that brings us now to memory, and I want to talk more about this in detail. So again, apps share a very limited amount of memory on these devices. So iOS 5 supports everything from an iPod Touch to an iPhone to an iPad, and they all have different amounts of memory, and some of them have a very limited amount of memory. And so you have to keep this in mind when you're developing your application.

And iOS will ensure that the device has the memory it needs to function. So even though there's this limited amount of memory on the device, it will try to make sure that the foreground application or a system processor, whatever that needs memory, can get that memory when it needs it. And to do that, you know, it does a couple of things. It first sends running apps memory warnings, asking them to free up memory.

And if it still needs to reclaim memory when it's under memory pressure, then it starts terminating applications one by one until it has enough memory for the foreground app or the system process to proceed. And so you kind of want to avoid it being terminated, if possible, because then your application has to relaunch completely when it comes back to the foreground.

So I want to talk a little bit more about memory warnings. If you haven't encountered memory warnings before, quite simply, iOS sends running applications a notification saying, "Hey, memory is tight right now. "Please free up some memory." And so this is the first thing it does to try and free up some memory.

And we did a lot of work in iOS 5 with the memory warning system, and your application should now only get memory warnings when it's absolutely crucial to free memory. So when you get that warning, you know, do please free up as much memory as you can because you may not get another chance to free up memory.

Now, I want to revisit that first point a bit. I said iOS sends notifications to running applications to free memory. And as Dave said earlier, when your application is sitting in the background, it's suspended, so it's not actually running on the CPU. And this is a bit of a subtle point because if you're using a whole bunch of memory when your application goes in the background and is suspended, it'll be sitting there in the background using that memory, and it won't get a chance to actually free that memory.

So when should you actually free up your memory? Well, when your app goes into the background before it's suspended. So at that point, you should just free up as much of your memory as you can. But there's this big tradeoff that you should keep in mind. To help your--to help your application free up memory, iOS itself and some of the frameworks in iOS will actually help--will free up some memory on your behalf, and we'll talk a little bit about And what's more, applications that end up using less than 16 megabytes of dirty memory while sitting in the background will actually have their dirty memory written out to disk and will have almost no memory footprint at all when they're sitting in the background. And that number is subject to change.

And here's that tradeoff that I alluded to earlier and didn't talk much about, but when you're freeing up memory, you should always balance the memory footprint in the background with the speed to resume. Because if you end up freeing so much memory when your application goes to the background, that it takes just as long to resume your application as to relaunch it from scratch, then we haven't really gained much. So now I want to talk a little bit more about what iOS and the system does for you and for your application as your application goes in the background so you can take better advantage of iOS. So first I want to talk about view backing stores.

So imagine that this multitasking icon that we have here is a custom drawn view. So it's a subclass of UIView. It overrides DrawRect and it uses core graphics to draw the graphics that you see here on the screen. So let's break this up into its constituent parts. hearts.

There's that UI view, which again is that subclass custom view. And then there's the bitmap image data that's actually displayed to the screen. So that multitasking icon, the blue icon now is that image data. And it turns out that in addition to these two pieces, there's also a CA layer. So UI view has a CA layer, and the CA layer actually has the big bitmap backing store.

And it turns out that every UI view on the system has a CA layer. And then these custom views that override DrawRect and draw their own contents have what we call this backing store, this bitmap backing store. And the Bitmap Backing Store is actually managed by Windows Server and Core Animation.

And when your application goes into the background, it can actually mark that backing store as something that can be reclaimed by iOS while your application is suspended if it needs it. So even if your application is suspended, there's this big chunk of memory in your application space that iOS can actually reclaim if it needs to. And it turns out that this backing store can be pretty big. And of the three pieces here, the UI view, the CA layer, and the backing store, the backing store usually ends up being the biggest part of this.

And so you can imagine that this is--this can free up quite a bit of memory or make quite a bit of memory available to the system when your application is in the background. If the contents or the backing store was reclaimed and used for something else while your app was in the background, when your application resumes to the foreground, iOS will call the draw rect again to get it back. to get the image data to display to the screen.

So another thing that iOS will do for you is related to the UI image cache. Some of you may know that UIKit will actually cache images loaded with UI image image named. Now, images can be really big and take up a lot of memory on iOS. In fact, they'll take up about four bytes per pixel is a good rule of thumb. But in addition, they take a long time to load. They take a long time to decompress and load and display on the screen. So UIKit will actually cache these images in memory that you load with this image named.

So as you load images one by one, they just keep piling up in memory. And you can--as you can imagine, it piles up pretty quickly and grows pretty--pretty quickly. But when your application goes into the background, UIKit will actually purge the cache completely and reclaim all of that memory for you.

And in a similar vein, several frameworks in iOS will actually cache data and memory to avoid going to the flash, or going to the network, or doing an expensive recalculation. And so these are frameworks like SQLite and Core Data and NSCache, which we'll talk about later, and a bunch of other frameworks. And when your application goes into the background, those frameworks will just empty those caches for you.

So those are a few things that iOS will actually do for you when your application enters the background to try and reduce your memory footprint. But now I want to talk about a few things that your app can do to free up some memory and make that memory available to other apps while your app's in the background. And first I want to talk about UI image views.

So as we talked about earlier, images can take up a lot of memory. And UI image views, like all UI views, have a CA layer. But in this case, instead of having a back-end store that's managed by Core Animation, the CA layer will use the contents of the image or the image data directly to display to the screen.

What this means is that these images are not reclaimed automatically when your app goes to the background. So if you're displaying this big 8 megapixel image in your view hierarchy somewhere, you're going to be using that much memory to keep that image in memory even when you're in the background.

So you should detach large images from your view hierarchy right before your application suspends and free up that memory and free up the image. And especially if those UI images are off screen, because if it's deep in a navigation controller or in a tab controller on an unselected tab, when your application resumes, you don't even need that image to actually resume.

But again, these images take a long time to decompress and load, so you should keep that in mind. If you are showing a really big UI image view when your application suspends and you get rid of it, when your application comes back to the foreground, then you have to pay the cost of decompressing the image before you can display it.

So again, that's part of that tradeoff that you have to keep in mind. Like, the more you release, the more time you will need to resume. You may want to make sure that your images are properly scaled before putting them into the UI image views, which could save you both the memory and the time to decompress.

So your application, similar to how some of iOS's frameworks caches data, might actually cache some data for the same reasons. To avoid hitting the flash, to avoid going to the network, to avoid some expensive calculations. And these caches can also build up. And so one of the other things your application can do to help the system manage memory is to flush your application caches as you go to the background. But again, not if resuming will take just as long as relaunching because of flushing all these caches. An interesting compromise though is to use NSCache with NSPurchableData.

So NSCache caches objects in memory. You know, not much of a surprise there. But it also manages and evicts these objects as necessary. So as it hits some limits or determines that it's a good time to evict some of these objects, it will actually automatically evict them for you and manage that. And there are different ways of configuring its eviction policy. And when you go into the background, it'll actually evict all the objects in your NS cache for you, so you're not paying the memory cost for all of that.

Now where NS Cache really shines is if you end up using it with NS purgeable data. So with NS purgeable data objects, you specify when you're using the data in the NS purgeable data and when you're done with it. And when you're done with the NS purgeable data object, the memory for that NS purgeable data object becomes reclaimable, very much like the backing stores for those custom views that we saw earlier. And so iOS can actually take the memory associated with those NS purgeable data objects if memory is tight.

And so if you put an NS purgeable data object into an NS cache, then it will actually stick around in the cache because it can actually be reclaimed by the OS even when your application is suspended. And so this has the benefit of if your applica-- if the user is switching quickly between your application and another application, as long as memory doesn't become tight or there's no memory pressure between them, when your application comes back to the front end or the foreground, much of this memory may actually still be there. So again, you specify when you want to use this NS purgeable data and when you're done with it. And when you're done with the NS purgeable data, they become reclaimable by the OS.

So another API or set of APIs that you may want to consider using are memory map files. So let's say you want to read a bunch of data from a file like this JPEG over here. Well, one option is to malloc a really big buffer or alloc init and NSData and just read it all from disk into this big buffer.

But the problem is that this big buffer is memory that the OS can't touch because it's part of your application's virtual memory. If you instead memory map the file, what happens is that the OS will reserve some space in your virtual memory address space for that file. But it doesn't actually assign any physical memory for the file yet. It's only when you start touching the pages and using the pages for that file that it actually brings in the data from the file and make it resident into memory.

And what's really cool is that when there's memory pressure and the OS needs some memory to use for some other purpose, if this file is mapped read only, then it can just go ahead and take one of these pages and throw it away and use that page for something else, because the next time your application touches that page, it can just bring it back in from the file. So it can do this even if your application is suspended in the background. So these memory map files are kind of a nicer way of reading in data from files when your application is suspended.

So consider mapping files into memory instead of reading them into in-memory buffers if possible. And to do so, you can use any number of the APIs we have, like NSData, data with contents of map file. And the real benefit is that iOS can reclaim these pages from map files automatically, even if your application is suspended.

So to summarize our best practices around memory, free up memory when you receive a memory warning. You may not get another chance to free up memory, so please do respond to the memory warnings. Free up memory when your application goes into the background as well, right before suspending.

Remove UI image views from the view hierarchy unless the decompression will be a problem when your application resumes. And consider using NSCache and memory map files and other memory-friendly APIs that we have in iOS. But always throughout all of this, remember the tradeoff to balance the memory footprint that you have in the background with how long it takes to resume your application.

So with that, I want to show now a short demo of some of the things we were talking about using the VM Tracker instrument. So I'm going to switch over to the iPad. And I wrote a couple of really simple applications here, and they're somewhat contrived, but they show the things that I wanted to talk about here. So the first one is this custom view application.

So you can't quite tell, but this custom view here that I have is a custom subclass of UIView, but it's really, really big. It's 8,000 by 8,000 pixels. So you would never create a view this big. But the backing store for this view takes up 8,000 by 8,000 pixels times four bytes per pixel, so about 256 megs.

And so then it just, it overrides drawRect and it draws that little apple using core graphics. So let's take a look at what this looks like in VM Tracker in Instruments. So I have Instruments here. And I'm going to select a blank document, launch the library, and find the VM Tracker instrument. And I'm just going to go ahead and drag that into Instruments.

And I'm going to attach to this custom view process here, so I can inspect its virtual memory space, and click record. So one thing to note about VM Tracker, and let me see if I can zoom in here for you. Oh, I can't. Is that it will snapshot the virtual memory space of the application at a regular interval if you set this, if you set an interval here. So see, so here I have it set to snapshot every three seconds.

And then it'll present to you some summary, some summary statistics of all the memory used by your application. So in this case, the summary statistics show that I have 245 megabytes of dirty memory. And dirty memory in general is memory that iOS can't touch and can't reclaim automatically.

And I'm going to switch here to the regions map, which will show each of the individual regions in the virtual memory space for this application, and then sort by dirty size. And at the top here, I have a region of type core animation that's 244 megabytes large. So this is the backing store for that view that we saw earlier.

So now I'm on the iPad and I'm going to go ahead and send that back to the background. And you can see when I did that, that this little flag up here showed up in Instruments. And if I click on that flag, it says that my application was background task suspended. So it went to the background and it's now suspended.

If I look back down here in the regions map, you'll see that I actually still have that big 244 megabyte region sitting around while my application is suspended. Now, this isn't really a big problem because, again, we've marked that as reclaimable while the application is in the background. So I'm going to switch back to the iPad and show you the other application that I wrote.

So I'm going to launch now this Photo Viewer application, and it's just this tab controller with two tabs. And I'm going to tap the second tab, which will show a 21 megapixel photo. And so, again, this will take up a huge amount of memory, about 80 megabytes of memory to show 21 megapixels. But I'm doing this to show you what happens when there's a bit of memory pressure on the system. And you saw also how long it took to actually load that. So let's switch back to instruments.

and look into the region map, and you'll see that, if you could read it, the big 250 megabyte core animation region is gone. And if I switch back to the summary, you'll see that my dirty size for my entire application is now 1.72 megabytes. So even though my application was suspended and never actually came back to the foreground, we were able to reclaim all that dirty memory and now it's just sitting in the background with very little dirty memory.

So this is the number you want to optimize for when your application is in the background. So I'm going to stop this trace and start Let's start a new trace now. and do the same thing loading the VM Tracker instrument into my workspace here. This time I'm going to attach to the photo viewer process that we just saw and start recording.

And so now you see this application has a dirty size, a total dirty size of about 85 megabytes, which is also really big. And so I'm going to switch over to the regions map and then sort by dirty again. And you see there's this one region here that's 80 megabytes large. And the type is memory tag 70.

And memory tag 70 turns out to be the, to be image memory. This is memory that iOS has allocated to decompress an image into. And so that's, that's the actual image data, the bitmap data for the image, the 21 megapixel image that was being displayed on the screen. So I'm going to send this to the background now. And so you can see again that flag showed up and said my application's background task suspended. And then now I'm going to launch that custom view again.

And you're going to have to trust me that I actually launched it, because you can see that this memory tag 70 with 80 megabytes dirty is still sitting around. So this is an example of those UI image views not being reclaimed as your application is sitting in the background. So this is something else you need to keep in mind when you're developing your application. And now I want to talk about another tricky resource, the GPU in OpenGL.

So as I said earlier, you know, the GPU is a really difficult resource for iOS to manage, so it terminates applications in the background if they try to use the GPU, if they try to use OpenGL. So it's really important if you're developing a game or using OpenGL, you probably have some kind of animation timer. It's really important to stop that animation timer as your application goes into the background. Because if you don't stop that animation timer, then you'll get a crash log that looks something like this.

So in this case, this application ended up calling glFinish while it was running in the background. Then after a bunch of calls, eventually it hit glrReturnNotPermittedKillClient, which is an indication that your application tried to use gl when it wasn't supposed to. And so the application is terminated. So this is a pretty tricky thing to get right, so I'm going to actually walk through a code sample for pausing the animation while your application is in the background.

So most of this code is from the GL template in Xcode. So you can go and check out the GL template if you want to pull out some of this code to use in your app. But this is from a view that uses OpenGL to draw to the screen.

And it has this method, startAnimation, on the view. And this method sets up the animation timer that will end up drawing to the screen. And to do so, it creates this display link. And a display link is very much like an NS timer in that you give it a selector, and then the display link just calls back that selector whenever it's advantageous to draw to the screen.

And so in that selector, this view will just do all of its GL drawing. Then it configures the timer, the display link, and then adds it to the run loop. So once it's added it to the run loop, then the timer starts calling that selector back to draw to the screen.

And then similarly it has the stop animation method. And the stop animation method just invalidates the timer and then sets it to no. It releases it. So now that we have a way to start and stop animation, we want to do so at the appropriate times. And this particular code is going to use the multitasking notifications that we saw earlier and not the explicit callbacks on the UI application delegate.

So in this view, when this view wakes up from its nib, the first thing it does, or one of the first things it does is it registers for the application will resign active notification. So you'll get this notification any time we'll call the application will resign active callback on the delegate, which is whenever the application goes into the background, when the user brings up the multitasking UI, whenever an alert style notification pops up over your application. All these cases, you'll get this callback and you really want to stop and pause your So in the method that observes this notification, all this view does is calls stop animation, if appropriate.

So now that the animation's paused, we probably want to resume it when it's appropriate to do so. So to do that, we're going to call the UI application to become active notification. And you get this when your application comes back to the foreground, when the user dismisses the multitasking UI, if the user had brought up the multitasking UI, or when the user dismisses an alert style notification as we talked about earlier. And then simply in the observer, it calls startAnimation.

Now, one other case that your application, your GL game, has to handle properly is termination. When your application terminates, you actually don't get that will resign active callback. But your application runs in the background for a short period of time to clean up. And if your application uses GL at any time when it's running in the background, it'll get terminated. So this view will also register for the UI application will terminate notification. And then, not a big surprise, in the observer, it calls stop animation. And so this prevents your application from being terminated ungracefully when it is about to be terminated.

[Transcript missing]

Now games, they're kind of divided into two categories. One is the turn-by-turn games. These are, I think, the easiest to preserve state in that you moved your checkerboard or your chess piece, or maybe you got past one little state in the level, and you kind of save your state after each turn.

So once something changes, maybe it's a game where people think a lot about, like a Scrabble-type game, people expect that when they return to your app, if after they finish the turn, that they return to exactly where they were. So it's a good idea for those sorts of games just to save when something changes.

But for some sorts of games, like, say, a first-person shooter or some other very heavy-duty OpenGL games, you have things that are changing at 60 frames per second. And for those types of games, you really want to be able to do all your graphics work during that 1/16th of a second that you have to generate a frame. And you don't want to be saving your state all the time.

So for those sorts of games, it's best to save at really important transitions. So some of those may be you change from one level to the other, or maybe you accomplish some sort of goal or achievement, or in between levels is another good place. And of course, you always want to save state in the background so that when the user returns to the app, they'll get to right at that point where they left off. So that's a few tips for games.

Beyond state preservation, there are some things that you want to do to make sure that your app is fully functional and works properly when it resumes. So, when you go into the background, maybe you had some networking socket that was open downloading some data, those may be disconnected while you are suspended. If you have a phone, you're constantly--you may drive down this road, you may go through a tunnel, lots of things can happen while you're in the background.

And so, you need to assume that that socket may disconnect at some point while you're suspended and you may have to candle some error conditions on resume or maybe reissue that networking query. And it's also important for any application that does a lot of networking that listens to things on the other end that suspended apps, because they're suspended, won't be able to accept incoming connections. So, if you have some sort of listening socket, make sure that you close that on suspend so that clients don't think that somebody is available to talk to.

and then of course reopen those on resume. And this is much the same as a Bonjour connections. If you have a Bonjour connection, or a Bonjour operation that's going, you need to assume that they'll be canceled when the application is suspended. So you have two people talking to each other, you don't want your application to go silent.

So you want to kind of cleanly tear down the Bonjour connection or service and then restart them on resume. There's a lot of detail that was covered in the Bonjour talk about this that I'd suggest checking out if you have an app that makes heavy use of Bonjour.

And then of course there's system notifications. So lots of things can happen in the background. User may--the most common one is they may go to your--our settings app, change some setting in the application--in the settings app and then return to your app. Or, you know, the user may change their language and there are a bunch of other things that can happen while you're in the background, but we don't want to have all background apps do a lot of work every time that we have a notification. So rather than sending all these notifications, either while you're in the background or trying to replay all of them when you enter the foreground, we instead coalesce and queue up the notifications.

So if you change your setting, you know, if the user changes your setting five different times or changes the language five different times or take some other action that triggers a notification, then we will take all of those, we'll queue them up and then on resume we'll deliver them to you. So that means that you won't get this giant replay of a ton of notifications, but still get them when you resume.

So just a couple of common ones. I think the most common one is the NSUserDefaultsDidChangeNotification, which you'll get when the user goes into the Settings app and changes a setting for your application. And there's also language or locale changes. And a much, much longer list of notification that's in the documentation of all sorts of various things that can change while your application is in the background. So if you listen to those anywhere, then you'll get them on resume.

Now last we want to cover a couple of little tidbits about several of the multitasking services. So the first one is task completion. So it's the second most important multitasking scenario, the first being fast app switching. And one of the great things is we have so many apps adopting it that users now expect it.

So if you're an app that downloads something, like something, say a 30 meg file, maybe it's a book, maybe it's something else, then users really expect that if they start the operation while your app is in the foreground, it will continue in the background. And so task completion isn't just a good idea now. It's actually a fairly strong requirement for users.

You know, it's worked out really well for a lot of applications. And so users will expect all applications to handle it--to handle this very, very gracefully and just finish whatever you're downloading. But of course, we only do this for the tasks where you really need to-- to continue the downloading and try to finish as quickly as possible. So don't download a bunch of extra data.

Just download what you need. And if you can't finish in time, if for some reason the user goes into a networking environment that wasn't as good as when they started or--and you realize that you can't finish in time, then you will get an expiration handler that fires a few seconds before your application is suspended. And at that point, you want to end the background task and store off where you were so that you can resume. When the application resumes. And ideally, you would store whatever you downloaded and just download the remaining bits when the user goes back to your application.

Now, background audio. So we provide all these great services to prioritize audio so that the user experience is really sane when you have all these different audio bits going on around the system like phone calls and music and alerts, et cetera. We provide all sorts of services for mixing and ducking and integration with headsets and external speakers. One thing that we're adding to iOS 5 is the ability to--you know, To use what we call the display remote.

So accessories have the ability to display album artwork and say the name of the track and some other data. And applications also get this too through the media player framework. So if you're a background audio application, you can present the same kinds of information that we do for the iPod app. And we think this will work out really great.

For audio applications, one important thing for users is to handle audio interruptions correctly. So during an interruption, such as a phone call, the audio system will silence an interupted application, and you'll want to update your UI appropriately and potentially resume after the interruption. So for example, if you are an application that plays audio persistently in the background and the user gets a phone call, we want you to resume that when the user is done with the phone call and continue right where you were left off.

But if you were an application that was interrupted because the user went to, say, the iPod application, then when the user is done with the iPod, we don't want to begin the old audio application. So sometimes we want you to begin playing after the interruption. Other times we don't. So in that beginner interruption, you might, say, stop your downloading stream, update various aspects of your UI, and stop the visualizations like Charles mentioned, stop the OpenGL.

And then when you get the N interruption with flags method, you either resume or not, whether or not this audio session property, AV audio session interruption flag should resume is set. So we tell you whether or not you should resume. All you need to do is make sure that you do. So for phone calls, as I mentioned, the audio should resume, but if the iPod interrupts, then the audio shouldn't resume.

So that's audio. Location tracking has a few different modes. There's, of course, the one that we're familiar with with GPS apps where you can continually updating GPS. But I think two of the really interesting ones beyond that for location are the ability to get notified when significant location changes happen. So this is a cellular granular notification that you get. And then region monitoring, which is geofencing. It allows you to get a notification when you enter or exit specific regions.

And we'll give you a brief idea of what kind of they mean in pictures. So for significant location changes, let's say that you are interested in whether or not the user got to this red dot that's halfway across--or all the way across the city. The way that this will work is, you know, as the eye fall on the moon, as the eye falls on the moon, you're going to get a notification.

And then, as the iPhone moves from cell tower to cell tower throughout the city, you'll get these location change events while you're in the background. So it's great in that you get updated when important things happen, and then you can figure out whether or not you're within that particular region.

So you can figure out whether or not you're in that particular region. But what you might really want, rather than something like this, is the ability to say, don't tell me about all these intermediate states where I'm moving from cell tower to cell tower. Just tell me when I'm entering this last region of interest.

And that's what region monitoring allows you to do. So region monitoring says, well, you may have moved from the cell tower, but we're paying attention to that and we're keeping track of where you are. And then when you finally hit this last location, the one that you were interested in, then you'll get the notification that you have entered the region. So this one is a lot better for battery life for this type of application.

And in fact, it's the API that we use in the reminders application for location-based reminders. It's been available to third parties since iOS 4. Now, the key point about that one is that region monitoring is only available on iPhone 4. It's not available on the iPhone 3GS because we do a lot of clever work with our baseband to make all of this work. But all of them will use a lot less power than GPS applications that require persistent updates. Both of them will resume your suspended applications.

The region monitoring will just do it less often and only when you really need it. And if your application has been terminated at some point, then we will relaunch the application so that you get those notifications. So it's basically everything that you would want to be able to see when significant changes happen or when you enter and exit specific regions.

Another service new to iOS 5 is the Newsstand service. So this one you can declare by adding a newsstand-content to UI background modes and add the UI newsstand app key to your Info.plist. And this provides you the ability to get about once per day content downloads via push notifications.

So you send a push notification and to say that, hey, content is available, and then we will launch the app or wake up your application and deliver it some payload. And then your application can schedule downloads to download the latest issue, and there's a lot of great integration to update the icon and present it in the new newsstand UI.

A few things that you need to be careful about for news-standard applications. The first one is you kind of want to minimize your resource downloads and make sure that they go into the caches directory. So we will hand you a URL for your download when the download is complete. And if you need to decompress that download, then you want to make sure that that ends up in your caches directory.

And the reason is that users tend to fill up their device. They buy the device that they need for whatever capacity that they need. They fill it up somewhat close to the limit. And all of the applications are vying for whatever is left. So if you have a bunch of applications that are using, say, 300 megabytes to store their content, then they'll be fighting with each other to some extent. Because if the device gets full, we need to try to find some place for the new content that's coming down. We want to update the latest content.

And so we'll evict some news-stand content and other things as space is needed. So if your download is smaller, then there's a greater chance that the user will return to your application just as it was. And of course, this will reduce battery life and increase the speed at which you get the content. And you'll also want to minimize the number of downloads. So we will often tell people to have one or two different downloads. So we'll also tell people to have one or two different downloads.

So to summarize, multitasking in iOS provides a lot of different services that do a lot of work on your behalf. If you want to go through the details of each of the multitasking services, the two talks from last year are a great resource, and the developer documentation has a lot of data as well.

Whenever you are in the foreground, you want to respond to memory warnings to be a good citizen, and minimize your background memory usage so that more applications can fit in the system, and the users will return to your application and all of the applications on the system a lot more quickly. You always want to make sure that you return exactly to where you were when you were suspended to provide that idea to the user to not have to think about whether or not the application was resumed or relaunched, and provide that kind of transparent application lifecycle.

And of course, when you do go into the background and free up your memory usage, make sure that you balance that with speed to resume. So you want to use a small amount of memory, but also resume really quickly. And with all of those things, and by using all these services, we think we can give a really great multitasking experience to users.

So for more information, you can contact Michael Jurowicz, and there's a lot of detailed resources in our developer documentation. And the couple of sessions that are worth checking out, there was a newsstand one earlier today, and there have been a couple of iOS performance sessions to also check out. In particular, if you want to find out even more about memory usage, they cover a lot of details there. So thanks for coming today, and enjoy your time at the party tonight.