11

Im developing an app that has to run in the background. It's a location based app, so it runs all the time, the OS doesn't kill it.

It should send some info every 10 secs(just for debugging), I set a timer once its in the background. I set a breakpoint in the function that should be executed every 10 secs, which is never called, but if I pause the app and then continue the timer is called, and then the timer is executed every 10 secs without problems, weird right?

I thought that the timer would be executing anyway when I wasn't debugging, but it isn't, same thing as if I didn't pause the debugging.

My question is WHY?? The timer is set correctly(I assume) since it works after pausing, but it's not.

Any ideas?

The way I set the timer is:

self.timer = [NSTimer scheduledTimerWithTimeInterval:10 target:self selector:@selector(doStuff) userInfo:nil repeats:YES];

And in the function I connect to a webservice.

Thanks.

Smoore
  • 732
  • 2
  • 10
  • 27
subharb
  • 3,374
  • 8
  • 41
  • 72
  • This is about timers, not debugging; fix your title, pls. And is "objective-c" the best you can do towards tagging this question? – matt Jan 20 '12 at 15:11
  • possible duplicate of [NSTimers running in background?](http://stackoverflow.com/questions/5901398/nstimers-running-in-background) – matt Jan 20 '12 at 15:42

2 Answers2

20

I have a similar app design and was stuck on the same thing. What I found somewhere on the internet is adding this type of statement applicationDidEnterBackground:

    UIBackgroundTaskIdentifier locationUpdater =[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
         [[UIApplication sharedApplication] endBackgroundTask:locationUpdater];
        locationUpdater=UIBackgroundTaskInvalid;
     } ]; 

This tells the os that you still have things going and not to stop it.

I have my timer attached to this function

 //this is a wrapper method to fit the required selector signature
- (void)timeIntervalEnded:(NSTimer*)timer {
     [self writeToLog:[NSString stringWithFormat:@"Timer Ended On %@",[NSDate date]]];
     [self startReadingLocation];
     [timer invalidate];
     timer=nil;
}

I set the timer in my my location manager delegate methods.

I feel your pain. I found that these things were super finicky. This is what worked for me. I hope it helps. I have found that there isn't any really restrictions in what you can do in the background.

utahwithak
  • 6,235
  • 2
  • 40
  • 62
  • Actually it didnt fix my whole problem. Now I get a crash log, apparently because I dont end the background task, and that is because the task should never finish as long as the app is in the background. The NStimer will repeat endlesly. Is that possible? or since it's a location app I should hook the actions to the GPS? – subharb Jan 23 '12 at 09:24
  • I'm not exactly sure what the crash is from. I am able to maintain a socket connection in the background so I'm pretty sure that you aren't restricted to just location based things. But as I said these problems are not the easiest to solve. Sorry I couldn't be of more help. My timer will run endlessly (as far as I have watched) one thing to check is printing out the backgroundTimeRemaining (it should never go down and be very large) – utahwithak Jan 23 '12 at 16:05
  • so let me understand. You do the "beginBackgroundTaskWithExpirationHandler" in the applicationDidEnterBackground. And when your NSTimer expires you dont again a "beginBackgroundTaskWithExpirationHandler", the one you did when it went to the background was enough, is that right? – subharb Jan 24 '12 at 18:31
  • 2
    That is correct, I have a timer outside the app delegate class that is constantly running/expiring/resetting. And just beginBackgroundTaskWithExpirationHandler right before it goes into the background. My timer method is exactly as I posted. Be sure that you have location in the background mode field in your plist – utahwithak Jan 24 '12 at 22:47
  • I've been going round and round on this and I can't get it done. So what you actually do is to "wake" the GPS when the timer expires so you have a new 10mins to do stuff, is that correct? – subharb Feb 01 '12 at 10:41
  • 2
    This worked perfectly for me except it needed __block before UIBackgroundTaskIdentifier. Thanks! – user1681673 Jun 17 '13 at 00:33
0

There might be restrictions on what you can do in the background. Try adding the timer to the run loop before going into the background. Even that might not work; it may be that the only code of yours that can run in the background is the code called by the Core Location methods you've signed up for (e.g. locationManager:didUpdate...). But my impression is that timers already running before you start to go into the background will continue to run.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • But that doesnt explain why if I debug it works. That's what I dont understand. I assume the app behaves the same way debugging or just running – subharb Jan 20 '12 at 15:45
  • I believe that if you had tried what I suggested (set up the timer while still in the foreground) it would have solved the problem. This is in fact probably the same as the solution you accepted. Your problem was that you were already backgrounded and your runloop had stopped running before you set up the timer. Pausing at a breakpoint and resuming while backgrounded gives your runloop a new chance to run, so at that point the timer was added to the runloop. That's guesswork but I believe it explains the phenomena. – matt Jan 20 '12 at 16:08