1. More Multitasking in iOS. Task Completion

    IMPORTANT: Yuval fixed the sample project. I’ve really appreciate your work and your fix Yuval. Thanks.

    So, last week we’ve talked about multitasking in iOS. Particularly, we talked about the basic set of API implemented by Apple that allows a non-concurrent environment where the application can switch between the foreground and the background real fast.

    Now we are taking about the cases where this is not enough, the small class of application that really benefits to be able to execute when in background:

    • Task Completion
    • Audio Playback
    • Navigation for Location Based Applications
    • Voice over IP

    And let me emphasize that these are special cases, and as Tim Peters put it in the Zen of Python, “Special cases aren’t special enough to break the rules.” Use them wisely.

    Task Completion

    This is, by far, the most useful and usable API introduced in iOS 4 and related to background code execution. The scenario is plain simple. The user just hit the home button, but the application is still running some process. In the days of iPhone OS 3, or earlier, the OS would kill the app, that’s it. No argument, no nothing. The boss hit the home button, that means you (the app) has to die.

    Now, when the home button is tapped, the app is briefly taken to the inactive state, and the to the running background state. Most applications are then quickly moved to the suspended state, but not the ones that ask the system to keep running until they are done with some task. Once the task is complete, the app needs to notify the system, and then it is going set as suspended.

    To identify the task we want the system to complete even if the application is send to background, the UIApplication class has added a new method:

    - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^)(void))handler; 
    

    This methods will return either UIBackgroundTaskInvalid if it is not possible to complete the task in background, or the actual task identifier (UIBackgroundTaskIdentifier). To understand the parameter we need to feed into this method, we first have to remember that the OS does not guaranteed that the task will be executed, but merely that it will keep working on the job on behalf of the user a little bit longer. Most of the time, this a little bit longer will suffice to get the job done, but it might not. In that case, the OS will try to suspend the app, and here is were the block we pass to beginBackgroundTaskWithExpirationHandler is going to be executed. This is the last chance for the application to get its act together. And since it is executed just before the app hit the timeout, there is no room for fancy stuff here. One important thing to have in mind is that this block might be executed in a separate thread.

    Then, we proceed to start the task as usual, and then, calls - endBackgroundTask: to let the OS that it can finish the task.

    - (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier; 
    

    This one takes the id produced by the afore mentioned. If you neglect to call - endBackgroundTask: and the process is not finished before the timeout the system will grant, the app is going to be terminated, and generate a crash log. Thus, the two call have to be balanced.

    You will find some sample code in github. The important snippet is:

    UIBackgroundTaskIdentifier bti = 
    [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [self stopCrunching]; 
    }];
    [self startCrunching]; 
    [[UIApplication sharedApplication] endBackgroundTask:bti];
    

    Now, repeat with me, this API is meant to complete some important task, and not to bypass the OS checkpoints and make your app run wild in the background. The OS will give the app a few more seconds to execute a process, but that’s it, eventually the app is going to be suspended. Remember, use this wisely.

    Best Practices

    When the app is running in the back thanks to task completion, the system will prioritize the foreground activity. Much of the system access is going to be degraded to the background task, including:

    • Access to CPU
    • Network I/O
    • File System Access

    Some other resources are strictly off limits, including:

    • GPU
    • Real-time Threads

    Also, don’t play against the timeout. If the task is done, just call it a day (and call - endBackgroundTask:)

Notes

  1. do-nothing reblogged this from volonbolon and added:
    (last week)[http://volonbolon.tumblr.com/post/1037215985/multitasking-in-ios]
  2. volonbolon posted this