So on this page there is an example about background execution: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1, here is the example:
- (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.
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
}
It is said that bgTask is defined in class as variable. So there is one bgTask property for every instance of class (object). If applicationDidEnterBackground were to be called multiple times before async block finishes, isn't here danger of race condition? I mean bgTask would change its value, and endBackgroundTask would be called on new task value, instead of old value?
Isn't here a better solution to do this:
__block UIBackgroundTaskIdentifier bgTask;
before calling beginBackgroundTaskWithName?
There is one instance of of
bgTaskfor each object, but this is on theAppDelegate, not some general VC or object. So there will technically only ever be onebgTaskinstance at work.But this still creates problems. Since if this method gets called twice it will override
bgTask's value. My first thought was that upon exiting the app, more than once, all previous tasks would expire. But after testing realized this was not the case (which is a good thing IMO). What did happen is thatbgTaskwas overwritten (as expected) and the new value was passed to the firstendBackgroundTask:call. Immediate afterwardbgTaskis set toUIBackgroundTaskInvalidwhich clears it out and the cleared value is passed to any subsequent calls toendBackgroundTask:. This obviously resulted in an unclean termination since not all the unique id's would have been ended, leading to theexpirationhandler executing on any left over background tasks.That being said, I believe your assumption about using a local variable is correct. If you try out this code (placed in the
AppDelegateapplicationDidEnterBackground:):You will see that each local
bgTaskis assigned a unique value and properly completed after 10 seconds (as per thedispatch_aftercall).