1

For some reason my timer only runs in the foreground. I've searched here for solutions but I couldn't find any good ones. My timer uses Core Data and my timeInterval is saved after every decrement. Also, I'm sending a UILocalNotification but that doesn't work. I'm assuming it doesn't send a alert view if its in the foreground..Well this is what I have now:

-(IBAction)startTimer:(id)sender{
    if (timer == nil) {
        [startButton setTitle:@"Pause" forState:UIControlStateNormal];
       timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
    } else {
        [startButton setTitle:@"Resume" forState:UIControlStateNormal];
        [timer invalidate];
        timer = nil;
    }

}
-(void)timerAction:(NSTimer *)t
{
    if(testTask.timeInterval == 0)
    {
        if (self.timer)
        {
            [self timerExpired];
            [self.timer invalidate];
            self.timer = nil;
        }
    }
    else
    {
        testTask.timeInterval--;
        NSError *error;
        if (![self.context save:&error]) {
            NSLog(@"couldn't save: %@", [error localizedDescription]);
        }
    }
    NSUInteger seconds = (NSUInteger)round(testTask.timeInterval);
    NSString *string = [NSString stringWithFormat:@"%02u:%02u:%02u",
                        seconds / 3600, (seconds / 60) % 60, seconds % 60];
    timerLabel.text = string;
    NSLog(@"%f", testTask.timeInterval);
}
-(void)timerExpired{
    UILocalNotification* localNotification = [[UILocalNotification alloc] init];
    localNotification.alertBody = @"Time is up";
    localNotification.alertAction = @"Ok";
    localNotification.timeZone = [NSTimeZone defaultTimeZone];
    [[UIApplication sharedApplication]presentLocalNotificationNow:localNotification];
}

I would really appreciate some guidance to making my timer work in the background (just like Apple's timer). I'm not sure how I would use NSDateComponents since I also need the testTask.timeInterval to be updated even when the application in the background..

EvilAegis
  • 733
  • 1
  • 9
  • 18
  • possible duplicate of [Problem in Background Thread in iPhone](http://stackoverflow.com/questions/7187967/problem-in-background-thread-in-iphone); see also [Problem while working in background and nstimer](http://stackoverflow.com/q/7190919) – jscs Aug 03 '13 at 23:43
  • 2
    You can't make the timer run while your app is backgrounded. If you're trying to display a countdown, you need to save the time when your app goes into the background and use that when you redisplay on becoming active again. There's multiple posts on this issue on SO. – jscs Aug 03 '13 at 23:44
  • did you tried that? `[[UIApplication sharedApplication] performSelector:@selector(presentLocalNotificationNow:) withObject:localNotification afterDelay:1.0];` where 1.0 is the time in seconds you want to wait. – lucaslt89 Aug 04 '13 at 01:56
  • possible duplicate of [How keep NSTimer when application entering background?](http://stackoverflow.com/questions/9840911/how-keep-nstimer-when-application-entering-background) – Caleb Aug 04 '13 at 02:31

2 Answers2

6
UIBackgroundTaskIdentifier bgTask =0;
UIApplication  *app = [UIApplication sharedApplication];
bgTask = [app beginBackgroundTaskWithExpirationHandler:^{
    [app endBackgroundTask:bgTask];
}];

NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
           target:self
           selector:@selector(timerCountDown:)
           userInfo:nil
           repeats:YES];

Now use this method to fire your notification. The timer will run in background.

3

As Josh Caswell wrote, you should save your timer state before your app goes in the background and then retrieve it when your app comes in the foreground again.

If you need to send a local notification at the right moment you can set it this way before entering the background, using your timer's state:

UILocalNotification *localNotification = [[UILocalNotification alloc] init];
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];

[dateFormat setDateFormat:@"yyyyMMddHHmmss"];   
    NSDate *when = [dateFormat dateFromString:desiredTime];
// desiredTime -> time you want your local notification to be fired, take this from your timer before app enters the background

[dateFormat release];

localNotification.fireDate = when;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.soundName = UILocalNotificationDefaultSoundName;

localNotification.alertBody = @"Hey";

[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

[localNotification release];

EDIT: In your appDelegate you should find these methods:

(1) - (void)applicationWillResignActive:(UIApplication *)application
(2) - (void)applicationDidEnterBackground:(UIApplication *)application
(3) - (void)applicationWillEnterForeground:(UIApplication *)application
(4) - (void)applicationDidBecomeActive:(UIApplication *)application
(5) - (void)applicationWillTerminate:(UIApplication *)application

These are implemented specifically to manage the behavior of your app when its state changes.

There you can do everything needed before entering the background and when resumed.

Before entering the background you have some seconds to perform local notification schedule and save your timer state (using for example NSUserDefaults).

After that Apple will probably kill your app, if it doesn't try to work in the background for one of these reasons:

Implementing Long-Running Background Tasks For tasks that require more execution time to implement,you must request specific permissions to run them in the background without their being suspended. In iOS, only specific app types are allowed to run in the background:

  • Apps that play audible content to the user while in the background, such as a music player app
  • Apps that keep users informed of their location at all times, such as a navigation app
  • Apps that support Voice over Internet Protocol (VoIP)
  • Newsstand apps that need to download and process new content
  • Apps that receive regular updates from external accessories

Taken from here.

I suggest you read this, about background tasks.

Community
  • 1
  • 1
Giuseppe Garassino
  • 2,272
  • 1
  • 27
  • 47