Ending Background Tasks

iOS 4 bought a host of new features and APIs. One of the most exciting for me was the ability to initiate long running tasks that have the ability to continue execution even after your application has moved into the background, that is once it is no longer running in the foreground.

The primary methods used to trigger this functionality are:

  • beginBackgroundTaskWithExpirationHandler:
  • endBackgroundTask:

Both methods are available on instances of UIApplication. Apple’s documentation for beginBackgroundTaskWithExpirationHandler: states:

Each call to this method must be balanced by a matching call to the endBackgroundTask: method.

These rules for background tasks are analogous to memory management rules within Objective-C, where it is crucial to balance retain and release calls. In either case the consequences are severe if you don’t get it right. For example if you do not call endBackgroundTask: for each task before its’ time expires, the system terminates the app.

If you do not call endBackgroundTask: for each task before time expires, the system terminates the application.

The exact amount of time your app is given is undefined. However, using the backgroundTimeRemaining method on UIApplication, your app can determine how much time is remaining at any point during execution.

The simplest use case may involve only one background task. However, depending upon your app’s requirements and/or complexity you may have many background tasks potentially being managed across disparate areas of your app.

If you’re working with background tasks I recommend you pay special attention to keeping the begin and end calls balanced. One useful strategy is to set a symbolic breakpoint on the UIApplicationEndBackgroundTaskError  function. This function is called when your app calls the endBackgroundTask: method with a backgroundTaskIdentifier that has already been ended or does not exist. You may also place a breakpoint within the expiration handler block that you pass into the beginBackgroundTaskWithExpirationHandler:  method.

These two breakpoints should allow you to catch any unexpected scenarios where you haven’t correctly balanced the two method calls. Just be sure to execute your app with breakpoints on during development!

iOS 4 and Disabling Multitasking

iOS 4 delivers long awaiting and much anticipated multitasking support for iOS apps. Detailed information on supporting multitasking in your app can be found via Apple’s iPhone Application Programming Guide. If you’ve installed iPhone SDK 4 and are now building apps with it, one very important point to note is:

Applications linked against iPhone OS 4 and later are automatically assumed to support multitasking and to implement the appropriate methods to handle transitions to the background state. However, work is still required to ensure that your application transitions smoothly between the foreground and background.

Therefore, if you set your Xcode project’s target to a Base SDK of 4.0, your application is expected to support multitasking. In some cases having your app moved to the background instead of being terminated may not be appropriate. It is possible to opt out of background execution by adding the UIApplicationExitsOnSuspend key to your project’s Info.plist and setting its’ value to YES. This effectively disables multitasking for your app and will force it to terminate instead of being suspended by the OS.

Objective-C: Categories and static libraries

After taking advantage of Objective-C categories to add some additional behaviour to NSArray and NSDictionary, I decided to extract the new classes I created into a static library. However, when running my application that made use of this static library, I received the following error:

unrecognized selector sent to instance

There is an Apple tech note that explains how to resolve this – QA1490

To resolve this issue, the static library should pass the -ObjC option to the linker. This flag causes the linker to load every object file in the library that defines an Objective-C class or category. While this option will typically result in a larger executable (due to additional object code loaded into the application), it will allow the successful creation of effective Objective-C static libraries that contain categories on existing classes.