在我的应用程序中,我正在将图像从 iPhone 上传到服务器。如果用户按主页按钮进行同步,则应用程序将关闭。
我希望应用程序必须在后台运行直到同步完成。
我的问题是:如何使用“ beginBackgroundTaskWithExpirationHandler
”添加当前正在运行的任务?
请分享你的想法。
在我的应用程序中,我正在将图像从 iPhone 上传到服务器。如果用户按主页按钮进行同步,则应用程序将关闭。
我希望应用程序必须在后台运行直到同步完成。
我的问题是:如何使用“ beginBackgroundTaskWithExpirationHandler
”添加当前正在运行的任务?
请分享你的想法。
尽管它的名字,beginBackgroundTaskWithExpirationHandler:
实际上并没有“开始”一个任务。将其视为“注册...”而不是“开始...”可能会更好。您只是在告诉系统您正在做某事,如果可以的话,您正在做一些想做的事情。
几点:
在几乎所有情况下,您都想beginBackgroundTaskWithExpirationHandler:
在开始做您想做的事情时打电话,然后endBackgroundTask:
在您完成时打电话。您几乎从不会在用户按下 Home 按钮时调用它们(除非那是您开始任务的时间点,例如将某些内容保存到服务器)。
您可以一次打开任意数量的“后台任务”。他们不花钱。它们就像保留计数。只要你还有一个打开的(一个“开始”,没有到达它的“结束”),那么系统就会认为这个请求需要更多的时间。调用“开始”和“结束”方法的成本非常低,所以使用它们来括号任何你想要额外时间完成的东西。
无法确定您将完成同步。这些方法只是发出请求。操作系统可能仍会拒绝该请求。只要操作系统需要一些额外的资源,它仍然可能会杀死你。操作系统不是无限耐心的;如果您花费的时间太长(通常大约 10 分钟),在调用过期处理程序后无论如何它都会杀死您。操作系统可能会因为手机被关闭而杀死你。您的应用程序必须能够处理无法完成的问题。操作系统只是为您提供了这种能力,以便您可以改善用户体验。
我将以下代码用于后台任务处理程序:
__block UIBackgroundTaskIdentifier backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"Background Time:%f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
[[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];
backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}];
下面是我使用 beginBackgroundTaskWithExpirationHandler 的方法,包括调用要在后台完成的方法。这包括用于启动新异步任务的代码。所以不完全是问题中的问题。在下面添加代码,认为有人可能正在寻找这种情况:
- (void)didReceiveObjList:(CFDataRef)message
{
// Received Object List. Processing the list can take a few seconds.
// So doing it in separate thread with expiration handler to ensure it gets some time to do the task even if the app goes to background.
UIApplication *application = [UIApplication sharedApplication];
__block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
}];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self processObjList:message];
[application endBackgroundTask:bgTask];
bgTask = UIBackgroundTaskInvalid;
});
NSLog(@"Main Thread proceeding...");
}
看看这个页面,Apple 描述了如何在后台保持 iOS 应用程序不被挂起。 苹果文档
这是我已经实现的:
UIBackgroundTaskIdentifier bgTask;
- (void)applicationDidEnterBackground:(UIApplication *)application
{
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
NSLog(@"=== DID ENTER BACKGROUND ===");
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
// [self askToRunMoreBackgroundTask]; This code seems to be unnecessary. I'll verify it.
}];
if (bgTask == UIBackgroundTaskInvalid) {
NSLog(@"This application does not support background mode");
} else {
//if application supports background mode, we'll see this log.
NSLog(@"Application will continue to run in background");
}
}
/*
- (void)askToRunMoreBackgroundTask
{
[[UIApplication sharedApplication] endBackgroundTask:bgTask];
NSLog(@"restart background long-running task");
bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
[self askToRunMoreBackgroundTask];
}];
}
*/
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSLog(@"=== GOING BACK FROM IDLE MODE ===");
//it’s important to stop background task when we do not need it anymore
[[UIApplication sharedApplication] endBackgroundTask:UIBackgroundTaskInvalid];
}
这是我在应用程序进入后台时使用的其他答案的轻微变化,我需要在主线程上做一些事情:
- (void)applicationWillResignActive:(UIApplication *)application
{
UIApplication *app = [UIApplication sharedApplication];
// Register auto expiring background task
__block UIBackgroundTaskIdentifier bgTaskId =
[app beginBackgroundTaskWithExpirationHandler:^{
[app endBackgroundTask:bgTaskId];
bgTaskId = UIBackgroundTaskInvalid;
}];
// Execute background task on the main thread
dispatch_async( dispatch_get_main_queue(), ^{
// ------------------
// DO SOMETHING INVOLVING THE WEBVIEW - WHICH MUST OCCUR ON THE MAIN THREAD!
// ------------------
[app endBackgroundTask:bgTaskId];
bgTaskId = UIBackgroundTaskInvalid;
});
}
您应该beginBackgroundTaskWithExpirationHandler
在应用程序将应用程序的状态更改为后台时运行您的任务或捕获通知,然后取消您当前的任务并使用beginBackgroundTaskWithExpirationHandler
.