0

My app needs to do some internet related operation then pop that view when I send the application to background. And then the root view controller fetches some data and updates the collection view. Do you have any idea how can I solve following issues related to above operations(by the way, I use local notifications to start the process):

1) UI related operations(popping current view controller) seems to fail in the background.

2) When I pop my view to root view controller, Root view has some nsurlconnection which sends data to its delegate. Since long running tasks run in global queue, nsurlconnection seems to fail sending any information to its delegate.

I use the following code for this process:

   UIBackgroundTaskIdentifier __block bgTask;
   UIApplication  *app = [UIApplication sharedApplication];
   bgTask = [app beginBackgroundTaskWithExpirationHandler:^{ 
         [app endBackgroundTask:bgTask]; 
         bgTask = UIBackgroundTaskInvalid;
    }];
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
         [self performOperation];
         NSLog(@"Operation finished");
     });
  • "UI related operations (popping current view controller) seems to fail in the background." If you are in the background you have no UI. That is (part of) what it means to be in the background. You need to rethink this entire architecture. – matt Jan 29 '14 at 19:56
  • Thanks for saving me many hours mate. – user1433743 Jan 29 '14 at 20:01

1 Answers1

-1

As matt pointed out, you can't do UI operations like popping the view controller when the app is in the background. When the app comes back to the foreground (e.g. the user taps on the icon again), the pop may take place then (if the app wasn't completely terminated in the interim).

I assume matt's observation answered your second question. If it didn't, please clarify what you mean. But this use of UIBackgroundTaskIdentifier doesn't care whether you used global queues or custom queues or whatever. The only restriction is that some UI operations will not take place, so anything contingent upon, for example, viewDidAppear, won't take place.

As an aside, I wanted to point out that you really want to call endBackgroundTask when the code that is doing the task completes, which your code sample does not appear to do. See the Executing a Finite-Length Task in the Background of the App States and Multitasking chapter of the iOS App Programming Guide.

Thus, you might do something like:

UIApplication *app = [UIApplication sharedApplication];

UIBackgroundTaskIdentifier __block bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    NSLog(@"Operation did not finish!!!");

    [app endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid;
}];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    [self performOperation];
    NSLog(@"Operation finished");

    if (bgTask != UIBackgroundTaskInvalid) {
        [app endBackgroundTask:bgTask];
        bgTask = UIBackgroundTaskInvalid;
    }
});
Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • I'm terribly sorry but you are just wrong. Calling `endBackgroundTask:` is _exactly_ what you do in `beginBackgroundTaskWithExpirationHandler:`. Indeed, it is usually _all_ you do there. This handler expresses, as you know, not the task, but what you will do if your time expires in the middle of the task - and calling `endBackgroundTask:` is exactly what you must do in that case, _or your app will be summarily terminated in the background_. It would be very bad to mislead the OP to believe otherwise. – matt Jan 29 '14 at 21:24
  • The structure of the OP's code is wrong, but not in the way you suggest. He should call `endBackgroundTask:` _both_ in the expiration handler _and_ at the end of the actual task. For a correct example, see my book: http://www.apeth.com/iOSBook/ch38.html#_threads_and_app_backgrounding – matt Jan 29 '14 at 21:28
  • @matt I was focusing the fact that he wasn't calling `endBackgroundTask` when his background task finished (causing the background session to always timeout, unnecessarily so), and not worrying about the state of the app when he had a genuine timeout. I've revised my answer accordingly. Thanks! – Rob Jan 29 '14 at 22:13