Search
Follow
Recent Comments

Entries in multitasking (3)

Wednesday
Jul072010

Flurry SDK 2.5 Issues

It seems that the latest release of the Flurry Analytics SDK is causing an issue with fast app switching with iOS 4. The issue which is easy to reproduce happens if, after you have sent a running App to background using the Home button, you immediately relaunch the app by tapping its icon on the desktop. Instead of the app being displayed you end up with a black screen. To exit the black screen you need to use the home button again. The Apple dev forums have some reports on the problem.

The default behaviour of Flurry is to send the analytics data as the app terminates. The latest version of the SDK (2.5) has been updated for iOS 4 and presumably (the release notes are not clear on this) also attempts to send data when the app moves to the background. Since this takes a few seconds (maybe more on a slow network) it seems that the app is not finishing before it gets relaunched.

The Flurry API does mention this as a potential issue and provides the option to send the data on startup:

[FlurryAPI setSessionReportsOnCloseEnabled:(BOOL)sendSessionReportsOnClose];

This option is on by default. When enabled, Flurry will attempt to send session data when the app is exited as well as it normally does when the app is started. This will improve the speed at which your application analytics are updated but can prolong the app termination process due to network latency. In some cases when setSessionReportsOnCloseEnabled is set to true, attempting to restart the application immediately (within a second) after exiting can cause a crash.

Setting this option to NO does seem to improve the performance but does not avoid it completely. In trying this with a test app I was still able to reproduce the black screen if I launched, exited and relaunched several times in quick succession. You could argue that this is not normal user behaviour but it still concerns me enough to avoid using Flurry until it gets sorted out.

Monday
Jul052010

Tracking background memory usage of iOS 4 apps

A quick follow up on yesterdays post about adding multitasking support to an iOS 4 app. I mentioned the recommendation from Apple to reduce your memory usage when entering background mode without mentioning how you determine what you are currently using.

VM Tracker

A new memory analysis instrument called VM Tracker was added to the Xcode Instruments tool with iPhone OS 3.1 to allow you to examine the virtual memory space of a process. Note that you need to be running on Snow Leopard to use VM Tracker. Unfortunately the documentation for VM Tracker does not yet seem to have made it into the Instruments User Guide so you have to look at the iPhone SDK Release Notes for iPhone OS 3.1 for details. The most interesting piece is on the Summary view:

Summary view - This view shows the total amount of memory by region type. Individual regions are grouped by region type and show their contribution to the type’s overall usage statistics. This view is primarily useful as an overview of how a process’ memory is being used, and it is recommended that special attention is paid to the “dirty” sizes, as these represent memory that must be paged to disk under memory pressure on Mac OS X and are completely unreclaimable memory on iPhone OS.

The “dirty” memory is what counts when an application is moved into the background and suspended. So this is the memory that needs to be reduced to a minimum if we want to increase the chances of surviving in the background.

To use the VM Tracker instrument run the application on a test device using the Run with Performance Tool > Allocations option from the Xcode Run menu. This will launch the application and attach Instruments to the running process with the Allocations and VM Tracker instruments.

The VM Tracker tool needs to suspend the app whilst taking a snapshot of its virtual memory so by default Apple has not enabled it to automatically snapshot the app. Since we are not in this case worried about impacting the application performance we can enable the Snapshot Automatically option with the default interval of 3 seconds. Alternatively you can manually click the Snapshot Now button after the app has entered the background and been suspended to record its memory usage.

With instruments running exercise the app to get a typical memory footprint and then use the home button to send it into the background. You should see two flags appear on the Instruments timeline. The first flag indicates that your app is entering the background (applicationDidEnterBackground is called at this point) and the second indicates the app has been suspended (click on the flag for details).

Once you have a snapshot of your app in the suspended state you can examine the VM Summary view to see the DIrty Size in MB (in the final column of the first row labeled *Dirty*). In the example below the app is using 5.90 MB.

I am still not sure what represents “High” memory utilisation so if you try this leave a comment for comparison but my feeling is that anything below 5-10 MB is “low” (time will tell if this is a good guess). What is probably more important is to go back and check your apps memory usage from time to time to ensure that it has not dramatically increased. The final test of whether an app is using too much memory is if users start to report that the app is being terminated by the system whilst in the background. Hopefully Apple will provide some feedback in the future on how they are seeing typical apps behave.

Sunday
Jul042010

Adding iOS4 Multitasking Support

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:

  • applicationDidBecomeActive
  • applicationWillResignActive
  • applicationDidEnterBackground
  • apllicationWillEnterForeground

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.

Cleanup UI

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.

Summary

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.