How to use beginBackgroundTaskWithExpirationHandler for already running task in iOS

前端 未结 6 1496
悲哀的现实
悲哀的现实 2020-11-28 03:10

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

I want app must be running in background till sync fini

相关标签:
6条回答
  • 2020-11-28 03:54

    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.

    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.

    0 讨论(0)
  • 2020-11-28 04:00

    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;
        });
    }
    
    0 讨论(0)
  • 2020-11-28 04:05

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

    0 讨论(0)
  • 2020-11-28 04:10

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

    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];  
    }
    
    0 讨论(0)
  • 2020-11-28 04:15

    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;
    }];
    
    0 讨论(0)
  • 2020-11-28 04:17

    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:

    - (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...");
    
    }
    
    0 讨论(0)
提交回复
热议问题