Proper Use of Beginbackgroundtaskwithexpirationhandler

Proper use of beginBackgroundTaskWithExpirationHandler

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)
}

How to use beginBackgroundTaskWithExpirationHandler for already running task in iOS

I used below code for background task handler:

__block UIBackgroundTaskIdentifier backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

NSLog(@"Background Time:%f",[[UIApplication sharedApplication] backgroundTimeRemaining]);

[[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];

backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}];

why beginBackgroundTaskWithExpirationHandler ending early?

There has never been a commitment from Apple on how long you would be allowed to perform your background tasks. Historically (until iOS7), apps were given usually 10 minutes to run in the background. This is no longer the case! Watch the WWDC 2013 video on backgrounding. With the addition of the new download & upload API in NSURLSession (ability to schedule download and upload tasks on an external dedicated daemon), Apple has reduced the allowed background time significantly. They've done this because this API has always been meant for download and upload, not arbitrary tasks in the background.

You can determine the amount of time left in background by querying - [UIApplication backgroundTimeRemaining]. You can use this to schedule your code to start at the latest possible.

beginBackgroundTaskWithExpirationHandler

You need to declare bgTask before you assign:

UIBackgroundTaskIdentifier bgTask = 0;

Should I use beginBackgroundTaskWithExpirationHandler: for all HTTP connections?

Yes. That is consistent with one of the design patterns described in the application design guide:

Wrap any long-running critical tasks with
beginBackgroundTaskWithExpirationHandler: and endBackgroundTask:
calls. This protects those tasks in situations where your application
is suddenly moved to the background.

Then in the expiration handler you can mark the upload as incomplete, and return to it in applicationDidBecomeActive:.

How should beginBackgroundTaskWithExpirationHandler: be used for the continuation of existing tasks?

You should just wrap it in the background task block anyway. Then if the app enters the background, you will be allowed to continue.

beginBackgroundTaskWithExpirationHandler never gets called

You are actually misunderstanding the function
-(UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler

The block argument called "handler" is what will happen when the background task expire (10min).

To get your code running you need to put your code out of the expiration handler:

UIApplication *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
bgTask = UIBackgroundTaskInvalid;
};

[self ffwButtonPressed:ffwButton];
NSLog(@"beginBG called");
[app endBackgroundTask:bgTask];

Here is a link to the documentation

using begin​Background​Task​With​Expiration​Handler​ for upload

This background task will let your app continue to run in background after the user leaves your app for an extra 3 minutes or so (check background​Time​Remaining for actual value) to let your request finish. And, yes, near the end of that 3 minutes, the timeout handler will be called if you haven't yet ended the background task.

So, if you end the background task during the normal flow of your app, this timeout closure won't need to be called. This closure is solely for any quick, last minute cleanup, that you might need to do before your app stops running in the background because it timed out before you had a chance to indicate that the background task ended. It's not for starting anything new, but just any last second clean-up. And make sure to end the background task in this timeout handler ... if you don't end the background task, the OS will summarily kill your app rather than just suspending it. Often, the only thing you need to do in this timeout closure is end the background task, but if you need to do any other cleanup, this is where you can do it.

Needless to say, you must end your background task (either when the network request finishes, or in the timeout handler if your app didn't yet get a chance to end the background task in its normal flow). If you don't, your app won't just be suspended, but rather it will be killed.

Regarding making assumptions about what happens when your app is restarted by the user later, you can't make any assumes about which app delegate method will be called. Even if you gracefully ended the background task, you have no assurances that it won't get jettisoned for other reasons (e.g. memory pressure). So don't assume anything.



Related Topics



Leave a reply



Submit