如何使用 beginBackgroundTaskWithExpirationHandler 在 iOS 中已经运行的任务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12071726/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 19:48:42  来源:igfitidea点击:

How to use beginBackgroundTaskWithExpirationHandler for already running task in iOS

iphoneiosbackground-process

提问by Vardhan

In my app, I am uploading images to server from iPhone. While sync if user press home button, App will close.

在我的应用程序中,我将图像从 iPhone 上传到服务器。同步时,如果用户按下主页按钮,应用程序将关闭。

I want app must be running in background till sync finish.

我希望应用程序必须在后台运行直到同步完成。

My question is: How can I add currently running task with "beginBackgroundTaskWithExpirationHandler"?

我的问题是:如何使用“ beginBackgroundTaskWithExpirationHandler”添加当前正在运行的任务?

Please share your ideas.

请分享您的想法。

采纳答案by Vardhan

I used below code for background task handler:

我在后台任务处理程序中使用了以下代码:

__block UIBackgroundTaskIdentifier backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{

    NSLog(@"Background Time:%f",[[UIApplication sharedApplication] backgroundTimeRemaining]);

    [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];

    backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}];

回答by Rob Napier

Despite its name, beginBackgroundTaskWithExpirationHandler:does not actually "begin" a task. It might be better thought of as "register..." rather than "begin...." You're just telling the system that you're in the middle of doing something that would like to complete if that's ok.

尽管它的名字,beginBackgroundTaskWithExpirationHandler:实际上并没有“开始”一项任务。最好将其视为“注册...”而不是“开始....”您只是告诉系统您正在做一些想要完成的事情,如果可以的话。

Several points:

几点:

  • In almost all cases, you want to call beginBackgroundTaskWithExpirationHandler:when you start doing the thing you want to do, and then endBackgroundTask:when you're done. You almost never call these at the point that the user presses the Home button (unless that's the point when you start the task, such as saving something to the server).

  • You can have as many "background tasks" as you want open at a time. They cost nothing. They're like retain counts. As long as you still have one open (a "begin" that did not get to its "end"), then the system will consider that a request for more time. There is very little cost to calling the "begin" and "end" methods, so use these to bracket anything that you want extra time to finish.

  • There is no way to be certain that you will get to finish your sync. These methods just make a request. The OS may still deny that request. The OS may still kill you anytime it needs some extra resources. The OS is not infinitely patient; if you take too long (about 10 minutes usually), it'll kill you anyway after calling your expiration handler. The OS may kill you because the phone is being turned off. Your app must be able to deal with not getting to finish. The OS just gives you this ability so that you can improve the user experience.

  • 在几乎所有情况下,您都希望beginBackgroundTaskWithExpirationHandler:在开始做想做的事情时调用,然后endBackgroundTask:在完成时调用。您几乎从不在用户按下主页按钮时调用它们(除非在您开始任务时,例如将某些内容保存到服务器)。

  • 您可以一次打开任意数量的“后台任务”。他们没有成本。它们就像保留计数。只要你还有一个打开的(一个“开始”没有到达它的“结束”),那么系统就会认为这是一个更多时间的请求。调用“begin”和“end”方法的成本非常低,因此可以使用这些方法将任何您希望额外时间完成的内容括起来。

  • 无法确定您将完成同步。这些方法只是发出请求。操作系统可能仍会拒绝该请求。操作系统在需要一些额外资源时仍可能会杀死您。操作系统不是无限耐心的。如果你花太长时间(通常大约 10 分钟),它会在调用到期处理程序后杀死你。操作系统可能会因为手机关机而杀死您。您的应用程序必须能够处理未完成的情况。操作系统只是为您提供此功能,以便您可以改善用户体验。

回答by Joe M

Here's how I used beginBackgroundTaskWithExpirationHandler, including the call to the method to be done in the background. This includes code for starting the new async task. So not exactly what is asked in the question. Adding code below, thinking someone might be looking for this scenario:

下面是我如何使用 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...");

}

回答by Duyen-Hoa

Take a look at this page, Apple describe how to keep iOS application not suspended while it is in background. Apple Documentation

看看这个页面,Apple 描述了如何在后台运行时保持 iOS 应用程序不被挂起。 苹果文档

And here is what I've implemented:

这是我实施的:

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];  
}

回答by BuvinJ

Here's a slight variation on the other answers which I'm using when the app is going to the background and I need to do something on the main thread:

当应用程序进入后台并且我需要在主线程上做一些事情时,我使用的其他答案略有不同:

- (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;
    });
}

回答by tikhop

You should run your task after beginBackgroundTaskWithExpirationHandleror capture notification when the application change app's state to background and then cancel your current task and run again with beginBackgroundTaskWithExpirationHandler.

您应该beginBackgroundTaskWithExpirationHandler在应用程序将应用程序的状态更改为后台时运行您的任务或捕获通知,然后取消当前任务并使用beginBackgroundTaskWithExpirationHandler.