因此,此页面上有一个有关后台执行的示例:https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1,这是示例:
- (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;
});
}
据说
bgTask
在类中定义为变量。因此,类(对象)的每个实例都有一个bgTask
属性。如果在异步块完成之前要多次调用applicationDidEnterBackground
,这不是竞争状态的危险吗?我的意思是bgTask
将更改其值,并且endBackgroundTask
将在新任务值而不是旧值上调用?这里不是更好的解决方案:
__block UIBackgroundTaskIdentifier bgTask;
在调用
beginBackgroundTaskWithName
之前? 最佳答案
每个对象都有一个bgTask
实例,但这是在AppDelegate
上,而不是某些常规VC或对象。因此,从技术上讲,只有一个bgTask
实例在工作。
但这仍然会产生问题。由于如果两次调用此方法,它将覆盖bgTask
的值。我的第一个想法是,退出该应用程序后,所有先前的任务都会多次失效。但是经过测试意识到情况并非如此(IMO很好)。确实发生的是bgTask
被覆盖(如预期的那样),并且新值已传递给第一个endBackgroundTask:
调用。之后立即将bgTask
设置为UIBackgroundTaskInvalid
,以将其清除,并将清除后的值传递给对endBackgroundTask:
的任何后续调用。显然,这导致了不干净的终止,因为并非所有唯一ID都将被终止,从而导致expiration
处理程序在任何剩余的后台任务上执行。
话虽如此,我相信您关于使用局部变量的假设是正确的。如果您尝试使用此代码(放置在AppDelegate
applicationDidEnterBackground:
中):
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
// Clean up any unfinished task business by marking where you
// stopped or ending the task outright.
NSLog(@"Expired");
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
NSLog(@"Backgrounded: %@", @(bgTask));
// 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.
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"Done! %@", @(bgTask));
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
});
您会看到,每个本地
bgTask
都分配了一个唯一值,并在10秒后正确完成(根据dispatch_after
调用)。