beginBackgroundTaskWithExpirationHandler调用endBackgroundTask但不是结束进程

时间:2015-04-28 12:29:50

标签: ios long-running-processes uibackgroundtask backgrounding

即使应用程序在后台运行,我也有一些长时间运行的进程。我正在调用应用程序的beginBackgroundTaskWithExpirationHandler:方法,而在expirationBlock中,我正在调用应用程序endBackgroundTask。 以下是实施:

__block UIBackgroundTaskIdentifier task = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    [[UIApplication sharedApplication] endBackgroundTask:task];
    task = UIBackgroundTaskInvalid;
}];
dispatch_queue_t queue = dispatch_queue_create("com.test.test1234", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
    // My Task goes here
});

在某些情况下,我的串行队列有更多要执行的任务,这些任务无法在系统提供的时间内完成。因此,到期阻止将执行,并且我将结束UIBackgroundTaskIdentifier,但不会停止调度过程(我甚至无法取消调度)。

Apple的文件说:

  

对beginBackgroundTaskWithName的每次调用:expirationHandler:或beginBackgroundTaskWithExpirationHandler:方法生成一个唯一的令牌以与相应的任务相关联。当您的应用程序完成任务时,它必须使用相应的令牌调用endBackgroundTask:方法,以让系统知道任务已完成。未能为后台任务调用endBackgroundTask:方法将导致应用程序终止。如果在启动任务时提供了过期处理程序,系统将调用该处理程序并为您提供最后一次结束任务并避免终止的机会。

所以,根据这个,如果我没有调用endBackgroundTask:我的应用程序将被终止,这没关系。

我的问题是:对于我当前的实现,如果我在expirationHandler块中调用endBackgroundTask:并且我的调度队列的任务没有完成,该怎么办?我的应用将被终止或暂停?

感谢

4 个答案:

答案 0 :(得分:12)

以下是使用beginBackgroundTaskWithExpirationHandler时需要处理的一些情况,否则您的应用将terminate

场景1 :您的应用正在Foreground中运行。您开始beginBackgroundTaskWithExpirationHandler然后进入Background模式。你的应用程序会保持很长时间。

场景2 :您的应用正在Foreground中运行。您开始beginBackgroundTaskWithExpirationHandler然后进入Background模式。然后回到Foreground模式,你没有打电话给endBackgroundTask,那么你的应用程序仍然是execute background queue所以它会扩展下一个3 minute的过程(在IOS 7介绍之后。在IOS之前) 7,过程执行时间为10分钟)。所以你必须取消后台队列和任务从后台队列中出来并进入前台队列

以下是向您展示的代码。什么是处理后台流程的最佳方式。

步骤1:将__block UIBackgroundTaskIdentifier bgTask声明为全局变量。

第2步:在applicationDidEnterBackground中添加以下代码。

- (void)applicationDidEnterBackground:(UIApplication *)application {

         bgTask = [application beginBackgroundTaskWithExpirationHandler:^{
         bgTask = UIBackgroundTaskInvalid;
          }];

}

第3步:一旦应用进入前台模式,就停止后台任务处理程序。

- (void)applicationWillEnterForeground:(UIApplication *)application {
  // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.

  [[UIApplication sharedApplication] endBackgroundTask:bgTask];

}

答案 1 :(得分:1)

如果您未在过期处理程序中调用endBackgroundTask,则您的应用将被终止。

在您的到期处理程序中调用endBackgroundTask之后,您只是告诉操作系统“好了,我已经完成了保存关键任务。现在由您决定。”之后,您的应用可能暂停一段时间并在稍后终止,或者可能会立即终止,具体取决于系统资源。

答案 2 :(得分:0)

演示代码的问题是您在用户任务过程中丢失了endBackgroundTask。

您应按以下方式使用:

__block UIBackgroundTaskIdentifier task = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
    [[UIApplication sharedApplication] endBackgroundTask:task];
    task = UIBackgroundTaskInvalid;
}];
dispatch_queue_t queue = dispatch_queue_create("com.test.test1234", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
    // My Task goes here

    // add new
    [UIApplication sharedApplication] endBackgroundTask:task];
    task = UIBackgroundTaskInvalid;
});

答案 3 :(得分:0)

@Jatin Patel 的答案很好。只需使用以下代码更改ApplicationWillEnterForeground的实现,以使您的应用程序永远不会终止

DispatchQueue.global(qos: .background).async {
    // sends registration to background queue
    application.endBackgroundTask(self.bgTask)
    self.bgTask = UIBackgroundTaskIdentifier.invalid
}