在我的应用程序中,我将图像从iPhone上传到服务器。如果用户按下主页按钮同步,则应用程序将关闭。
我希望app必须在后台运行,直到同步完成。
我的问题是:如何使用“beginBackgroundTaskWithExpirationHandler
”添加当前正在运行的任务?
请分享您的想法。
答案 0 :(得分:99)
尽管它的名字,beginBackgroundTaskWithExpirationHandler:
实际上并没有“开始”任务。它可能更好地被认为是“注册......”而不是“开始......”你只是告诉系统你正在做一些想要完成的事情,如果可以的话。
有几点:
几乎在所有情况下,您都希望在开始做想要做的事情时调用beginBackgroundTaskWithExpirationHandler:
,然后在完成后调用endBackgroundTask:
。您几乎从不在用户按下主页按钮时调用这些内容(除非这是您启动任务时的重点,例如将某些内容保存到服务器)。
您可以一次打开任意数量的“后台任务”。他们什么都不花钱他们就像保留计数。只要你还有一个打开(一个“开始”没有达到它的“结束”),那么系统会考虑更多时间的请求。调用“开始”和“结束”方法的成本非常低,因此请使用这些方法来包含任何您想要花费额外时间的内容。
无法确定您是否可以完成同步。这些方法只是提出请求。操作系统仍可能拒绝该请求。操作系统可能仍然会在需要一些额外资源时终止您。操作系统不是无限耐心;如果你花了太长时间(通常大约10分钟),它会在你调用你的到期处理程序之后杀死你。操作系统可能会因为手机被关闭而导致您死亡。您的应用必须能够处理无法完成。操作系统只为您提供此功能,以便您可以改善用户体验。
答案 1 :(得分:14)
我在下面的代码中使用了后台任务处理程序:
__block UIBackgroundTaskIdentifier backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(@"Background Time:%f",[[UIApplication sharedApplication] backgroundTimeRemaining]);
[[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];
backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}];
答案 2 :(得分:9)
这是我如何使用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...");
}
答案 3 :(得分:6)
看一下这个页面,Apple描述了如何让iOS应用程序在后台处于暂停状态。 Apple Documentation
以下是我实施的内容:
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];
}
答案 4 :(得分:4)
这是我在应用程序进入后台时使用的其他答案略有不同,我需要在主线程上执行某些操作:
- (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;
});
}
答案 5 :(得分:1)
您应该在beginBackgroundTaskWithExpirationHandler
之后运行任务,或者在应用程序将应用程序的状态更改为后台时捕获通知,然后取消当前任务并使用beginBackgroundTaskWithExpirationHandler
再次运行。