1

I've an app which run in background, and I want to stop all location services 30 min after entering into background mode.

So in my background function, I do this :

// 1800 sec = 30 min * 60 sec.
NSDate *date30min = [[NSDate alloc] initWithTimeIntervalSinceNow:1800.0];
NSLog(@"Date30min : %@", date30min);

self.timer = [[NSTimer alloc] initWithFireDate:date30min interval:1 target:self selector:@selector(stopLocation) userInfo:nil repeats:NO];

And my stopLocation function is :

- (void)stopLocation
{
    NSLog(@"[My APP] [PASS INTO stopLocation]");
    [self.locationManager stopMonitoringSignificantLocationChanges];
    [self.locationManager stopUpdatingLocation];
    [self.locationManager stopUpdatingHeading];
}

But my timer never call the function, what's my error please ? (My function is correctly implement into my .h and .m file, I tested this out of the background function.

Please help..

James Paolantonio
  • 2,194
  • 1
  • 15
  • 32
  • 1
    Don't you have to add the timer to the current run loop? –  Sep 06 '12 at 19:33
  • No, this timer is simply into the - applicationDidEnterBackground method, with many code before to launch correcty background tasks, when I NSLog(@"check"); just before try the timer, this log works, but no timer... – user1448932 Sep 06 '12 at 19:38
  • 2
    @userXXX so it seems you didn't understand what I meant... –  Sep 06 '12 at 19:43
  • 1
    The problem is that once your app enters background, it will not run anymore. So the timer won't fire unless your app becomes active again. – 0xced Sep 06 '12 at 20:42

1 Answers1

2

It's not a problem with forgetting to add your timer to a run loop (in this case).

NSTimer objects don't fire when your app goes into the background. So, I would use another technique if you want to do something 30 minutes after backgrounding.

For example, use a Background Task to run your stopLocation method later:

- (void)applicationDidEnterBackground:(UIApplication *)application {       

    __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler: ^{
         NSLog(@" expiration handler!"); 
    }];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 30 * 60 * NSEC_PER_SEC), dispatch_get_current_queue(), ^{

         [self stopLocation];

         // we're done with this task now
         [application endBackgroundTask: bgTask]; 
         bgTask = UIBackgroundTaskInvalid;
    });
}

Of course, you also need to have declared this:

<key>UIBackgroundModes</key>
<array>
    <string>location</string>
</array>

in your Info.plist file, but I assume you already figured that out.

Nate
  • 31,017
  • 13
  • 83
  • 207
  • Thank's to this great answer, now I understand why it wasn't running ! – user1448932 Sep 07 '12 at 07:16
  • @user1448932, yeah, this one has bitten me before, too! I can't imagine that very many people learn about this issue, **before** stumbling into it, when they just don't see their timers firing any more. – Nate Sep 07 '12 at 07:28
  • +1 mate, I thought he wanted to stop the background process by calling the function on the main thread. I will remove my post if you think my post wont be helpful for future viewers. – John Riselvato Sep 08 '12 at 07:52
  • @JohnRiselvato, I would probably remove it. Your answer certainly is a correct way to **normally** start a `NSTimer` object. It's just that in this case, the more fundamental problem is that he's trying to schedule something to happen when his app is already in the background, and for that, the timer isn't really the right tool for the job. – Nate Sep 08 '12 at 09:00