1

I have some NSOperations that are started regularly in my application. They should complete even when the the application is put to background. For this, I'm using the beginBackgroundTaskWithExpirationHandler method.

Am I supposed to use the beginBackgroundTaskWithExpirationHandler/ endBackgroundTask: every time I start my task even if the app is not going to background? Or am I supposed the call the begin/end methods only when I detected a UIApplicationDidEnterBackgroundNotification?

Option 1: Use background task every time

/**
 * This method is called regularly from a NSTimer
 */
- (void)processData
{
    __block UIBackgroundTaskIdentifier operationBackgroundId = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        [[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
        operationBackgroundId = UIBackgroundTaskInvalid;
    }];

    NSOperation *operation = ...
    [self.queue addOperation:operation];

    operation.completionBlock = ^{
        [[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
        operationBackgroundId = UIBackgroundTaskInvalid;
    };
}

Option 2: Use background task only when the application is about to go to background

/**
 * This method is called regularly from a NSTimer
 */
- (void)processData
{

    NSOperation *operation =  ...
    [self.queue addOperation:operation];

}


- (void)applicationDidEnterBackground:(NSNotification *)notification
{
    __block UIBackgroundTaskIdentifier operationBackgroundId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:@"EnterBackgroundFlushTask" expirationHandler:^{
        [[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
        operationBackgroundId = UIBackgroundTaskInvalid;
    }];

    // wait for all operations to complete and then


    // let UIApplication know that we are done
    [[UIApplication sharedApplication] endBackgroundTask:operationBackgroundId];
}
Jan
  • 7,444
  • 9
  • 50
  • 74
  • Are you sure that beginBackgroundTaskWithExpirationHandler: always returns value before expiration handler is called? Otherwise operationBackgroundId is wrong in expiration handler when it is called synchronously. Doc says that it can return also invalid - maybe this is the case when expiration handler is called before returning value. – Ariel Bogdziewicz Jan 31 '19 at 15:55

2 Answers2

7

Answering my own question. From the Apple Docs:

You do not need to wait until your app moves to the background to designate background tasks. A more useful design is to call the beginBackgroundTaskWithName:expirationHandler: or beginBackgroundTaskWithExpirationHandler: method before starting a task and call the endBackgroundTask: method as soon as you finish. You can even follow this pattern while your app is executing in the foreground.

Other Apple API reference:

You should call this method at times where leaving a task unfinished might be detrimental to your app’s user experience.

You can call this method at any point in your app’s execution.

Community
  • 1
  • 1
Jan
  • 7,444
  • 9
  • 50
  • 74
-2

Option2 is correct option.Here is code from Apple document for your reference.

 - (void)applicationDidEnterBackground:(UIApplication *)application
{
    bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
        // 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.

        [self processData];
        [application endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    });
}

Apple developer Guide

Ganesh Amrule
  • 407
  • 2
  • 12
  • But the Apple Documentation says: "You should call this method at times where leaving a task unfinished might be detrimental to your app’s user experience. You can call this method at any point in your app’s execution" https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instm/UIApplication/beginBackgroundTaskWithExpirationHandler – Jan Sep 12 '16 at 11:43
  • The problem with Option 2 is that I have to keep track on what has been started and what not. The example code is trivial but the real code is more complex – Jan Sep 12 '16 at 11:45
  • Actually, in the same link you posted, Apple say: "You do not need to wait until your app moves to the background to designate background tasks. A more useful design is to call the beginBackgroundTaskWithName:expirationHandler: or beginBackgroundTaskWithExpirationHandler: method before starting a task and call the endBackgroundTask: method as soon as you finish. You can even follow this pattern while your app is executing in the foreground." – Jan Sep 12 '16 at 11:50
  • I agree with @Jan – jlmg5564 Feb 14 '17 at 08:01
  • as a follow up, I've been using the Option 1 for a while now in my live apps and it works as expected and didn't have any issues – Jan Feb 14 '17 at 08:05
  • Can I have the swift version of this please? – Abhishek Jan 11 '18 at 07:39