Search code examples
iosobjective-cnetwork-programmingmultitaskingbackground-thread

Proper use of beginBackgroundTaskWithExpirationHandler


I'm a bit confused about how and when to use beginBackgroundTaskWithExpirationHandler.

Apple shows in their examples to use it in applicationDidEnterBackground delegate, to get more time to complete some important task, usually a network transaction.

When looking on my app, it seems like most of my network stuff is important, and when one is started I would like to complete it if the user pressed the home button.

So is it accepted/good practice to wrap every network transaction (and I'm not talking about downloading big chunk of data, it mostly some short xml) with beginBackgroundTaskWithExpirationHandler to be on the safe side?


Solution

  • If you want your network transaction to continue in the background, then you'll need to wrap it in a background task. It's also very important that you call endBackgroundTask when you're finished - otherwise the app will be killed after its allotted time has expired.

    Mine tend look something like this:

    - (void) doUpdate 
    {
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            
            [self beginBackgroundUpdateTask];
            
            NSURLResponse * response = nil;
            NSError  * error = nil;
            NSData * responseData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];
            
            // Do something with the result
            
            [self endBackgroundUpdateTask];
        });
    }
    - (void) beginBackgroundUpdateTask
    {
        self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
            [self endBackgroundUpdateTask];
        }];
    }
    
    - (void) endBackgroundUpdateTask
    {
        [[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
        self.backgroundUpdateTask = UIBackgroundTaskInvalid;
    }
    

    I have a UIBackgroundTaskIdentifier property for each background task


    Equivalent code in Swift

    func doUpdate () {
        
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
            
            let taskID = beginBackgroundUpdateTask()
            
            var response: URLResponse?, error: NSError?, request: NSURLRequest?
            
            let data = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error) {
            
            // Do something with the result
            
            endBackgroundUpdateTask(taskID)
            
            })
    }
    
    func beginBackgroundUpdateTask() -> UIBackgroundTaskIdentifier {
        return UIApplication.shared.beginBackgroundTask(expirationHandler: ({}))
    }
    
    func endBackgroundUpdateTask(taskID: UIBackgroundTaskIdentifier) {
        UIApplication.shared.endBackgroundTask(taskID)
    }