Background Execution and Multitasking

Background Execution and Multitasking

In iOS 4 and later, multitasking allows apps to continue running in the background even after the user switches to another app while still preserving battery life as much as possible. Most apps are moved to the suspended state shortly after entering the background. Only apps that provide important services to the user are allowed to continue running for any amount of time.

As much as possible, you are encouraged to avoid executing in the background and let your app be suspended. If you find you need to perform background tasks, here are some guidelines for when that is appropriate:

  • You need to implement at least one of several specific user services.

  • You need to perform a single finite-length task.

  • You need to use notifications to alert the user to some relevant piece of information when your app is not running.

The system keeps suspended apps in memory for as long as possible, removing them only when the amount of free memory gets low. Remaining in memory means that subsequent launches of your app are much faster. At the same time, being suspended means your app does not drain the device’s battery as fast.

Determining Whether Multitasking Is Available

Apps must be prepared to handle situations where multitasking (and therefore background execution) is not available. Even if your app is specifically built for iOS 4 and later, some devices running iOS 4 may not support multitasking. And multitasking is never available on devices running iOS 3 and earlier. If your app supports these earlier versions of iOS, it must be prepared to run without multitasking.

If the presence or absence of multitasking changes the way your app behaves, check the multitaskingSupported property of the UIDevice class to determine whether multitasking is available before performing the relevant task. For apps built for iOS 4 and later, this property is always available. However, if your app supports earlier versions of the system, you must check to see whether the property itself is available before accessing it, as shown in Listing 3-2.

Listing 3-2  Checking for background support in earlier versions of iOS

UIDevice* device = [UIDevice currentDevice];
BOOL backgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
   backgroundSupported = device.multitaskingSupported;

Executing a Finite-Length Task in the Background

Apps that are transitioning to the background can request an extra amount of time to finish any important last-minute tasks. To request background execution time, call the beginBackgroundTaskWithExpirationHandler: method of the UIApplication class. If your app moves to the background while the task is in progress, or if your app was already in the background, this method delays the suspension of your app. This can be important if your app is performing some important task, such as writing user data to disk or downloading an important file from a network server.

The way to use the beginBackgroundTaskWithExpirationHandler: method is to call it before starting the task you want to protect. Every call to this method must be balanced by a corresponding call to the endBackgroundTask: method to mark the end of the task. Because apps are given only a limited amount of time to finish background tasks, you must call this method before time expires; otherwise the system will terminate your app. To avoid termination, you can also provide an expiration handler when starting a task and call the endBackgroundTask: method from there. (You can use the value in the backgroundTimeRemaining property of the app object to see how much time is left.)

Important: An app can have any number of tasks running at the same time. Each time you start a task, the beginBackgroundTaskWithExpirationHandler: method returns a unique identifier for the task. You must pass this same identifier to the endBackgroundTask: method when it comes time to end the task.

Listing 3-3 shows how to start a long-running task when your app transitions to the background. In this example, the request to start a background task includes an expiration handler just in case the task takes too long. The task itself is then submitted to a dispatch queue for asynchronous execution so that the applicationDidEnterBackground: method can return normally. The use of blocks simplifies the code needed to maintain references to any important variables, such as the background task identifier. The bgTask variable is a member variable of the class that stores a pointer to the current background task identifier and is initialized prior to its use in this method.

Listing 3-3  Starting a background task at quit time

- (void)applicationDidEnterBackground:(UIApplication *)application
{
    bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
        // Clean up any unfinished task business by marking where you.
        // stopped or ending the task outright.
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }];
 
    // Start the long-running task and return immediately.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
 
        // Do the work associated with the task, preferably in chunks.
 
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    });
}

Note: Always provide an expiration handler when starting a task, but if you want to know how much time your app has left to run, get the value of the backgroundTimeRemaining property of UIApplication.

In your own expiration handlers, you can include additional code needed to close out your task. However, any code you include must not take too long to execute because, by the time your expiration handler is called, your app is already very close to its time limit. For this reason, perform only minimal cleanup of your state information and end the task.

Scheduling the Delivery of Local Notifications

Notifications are a way for an app that is suspended, is in the background, or is not running to get the user’s attention. Apps can use local notifications to display alerts, play sounds, badge the app’s icon, or a combination of the three. For example, an alarm clock app might use local notifications to play an alarm sound and display an alert to disable the alarm. When a notification is delivered to the user, the user must decide if the information warrants bringing the app back to the foreground. (If the app is already running in the foreground, local notifications are delivered quietly to the app and not to the user.)

To schedule the delivery of a local notification, create an instance of the UILocalNotification class, configure the notification parameters, and schedule it using the methods of the UIApplication class. The local notification object contains information about the type of notification to deliver (sound, alert, or badge) and the time (when applicable) at which to deliver it. The methods of the UIApplication class provide options for delivering notifications immediately or at the scheduled time.

Listing 3-4 shows an example that schedules a single alarm using a date and time that is set by the user. This example configures only one alarm at a time and cancels the previous alarm before scheduling a new one. (Your own apps can have no more than 128 local notifications active at any given time, any of which can be configured to repeat at a specified interval.) The alarm itself consists of an alert box and a sound file that is played if the app is not running or is in the background when the alarm fires. If the app is active and therefore running in the foreground, the app delegate’s application:didReceiveLocalNotification: method is called instead.

Listing 3-4  Scheduling an alarm notification

- (void)scheduleAlarmForDate:(NSDate*)theDate
{
    UIApplication* app = [UIApplication sharedApplication];
    NSArray*    oldNotifications = [app scheduledLocalNotifications];
 
    // Clear out the old notification before scheduling a new one.
    if ([oldNotifications count] > 0)
        [app cancelAllLocalNotifications];
 
    // Create a new notification.
    UILocalNotification* alarm = [[UILocalNotification alloc] init];
    if (alarm)
    {
        alarm.fireDate = theDate;
        alarm.timeZone = [NSTimeZone defaultTimeZone];
        alarm.repeatInterval = 0;
        alarm.soundName = @"alarmsound.caf";
        alarm.alertBody = @"Time to wake up!";
 
        [app scheduleLocalNotification:alarm];
    }
}

Sound files used with local notifications have the same requirements as those used for push notifications. Custom sound files must be located inside your app’s main bundle and support one of the following formats: Linear PCM, MA4, µ-Law, or a-Law. You can also specify the sound name default to play the default alert sound for the device. When the notification is sent and the sound is played, the system also triggers a vibration on devices that support it.

You can cancel scheduled notifications or get a list of notifications using the methods of the UIApplication class. For more information about these methods, see UIApplication Class Reference. For additional information about configuring local notifications, see Local and Push Notification Programming Guide.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值