Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Background task stopping when device locked?

I have a timer running when the device enters the background as I want to keep a check on a small amount of data in my service. I am using the following code in the applicationDidEnterBackground method in app delegate

    UIApplication *app = [UIApplication sharedApplication];

//create new uiBackgroundTask
__block UIBackgroundTaskIdentifier bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    [app endBackgroundTask:bgTask];
    bgTask = UIBackgroundTaskInvalid;
}];

//and create new timer with async call:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //run function methodRunAfterBackground
    NSString *server = [variableStore sharedGlobalData].server;
    NSLog(@"%@",server);
    if([server isEqual:@"_DEV"]){
        arrivalsTimer = [NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(getArrivals) userInfo:nil repeats:YES];
    }
    else {
        arrivalsTimer = [NSTimer scheduledTimerWithTimeInterval:300 target:self selector:@selector(getArrivals) userInfo:nil repeats:YES];
    }
    [[NSRunLoop currentRunLoop] addTimer:arrivalsTimer forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
});

This works absolutely fine, until the device auto-locks and then the timer stops ticking. Any suggestions on how to stop this from happening? The default live time is 5 minutes so the majority of devices will be locked long before this even ticks once.

Thanks

like image 243
Tony Law Avatar asked May 15 '15 15:05

Tony Law


1 Answers

A couple of observations:

  1. As Mr. H points out, beginBackgroundTaskWithExpirationHandler only gives you 30 seconds (previously 3 minutes) in contemporary iOS versions. So an attempt to fire a timer in five minutes won't work.

    You can use [[UIApplication sharedApplication] backgroundTimeRemaining] to inquire as to how much time you have left.

  2. When the device locks, the background tasks continue. You should not see the app terminating. If the user manually terminates the app through the "double tap the home button and swipe up on task switcher screen", that will kill the background tasks, but not simply locking the device.

  3. A few comments on timers:

    • The code is adding timer to background queue. That's generally not necessary. Just because the app is in a background state, you can still continue to use the main run loop for timers and the like.

      So, just call scheduledTimerWithTimeInterval from the main thread and you're done. There's no point in using up a GCD worker thread with a run loop unless absolutely necessary (and even then, I might create my own thread and add a run loop to that).

      By the way, if it's absolutely necessary to schedule timer on some background dispatch queue, it's probably easier to use dispatch timer instead. It eliminates the run loop requirement entirely.

    • BTW, it's not appropriate to use scheduledTimerWithTimeInterval with addTimer. You call scheduledTimerWithTimeInterval to create a timer and add it to the current run loop. You use timerWithTimeInterval and then call addTimer if you want to add it to another run loop.

like image 77
Rob Avatar answered Nov 02 '22 15:11

Rob