Search code examples
iosios7nsdatenstimernstimeinterval

iOS how to call a method on the minute, every minute


I mean 12:01:00, 12:02:00 ...

In iOS7, I want to call a method when minute of time is changed. In other words, if now is 01:55:47, then I want to call a method at 01:56:00 -> 01:57:00 -> 01:58:00 ...

All I found about call a method is just about TimeInterval, but not I want.

I've tried this code:

NSTimeInterval roundedInterval = round([[NSDate date] timeIntervalSinceReferenceDate] / 60.0) * 60.0;
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:roundedInterval];

NSTimer *timer = [[NSTimer alloc] initWithFireDate:date
                                          interval:60.0
                                            target:self
                                          selector:@selector(handleEveryMinutes:)
                                          userInfo:nil
                                           repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];

- (void)handleEveryMinutes:(NSTimer *)timer {
NSLog(@"one minute!");
}

But this method is not called at second 0.

Hope cool people can help me!

----- My answer -------

I also figure out why my code is not working correctly, I need add extra 60 seconds to the roundedInterval, which is the exact time of the next minute. If do not add 60 second, the fireDate is passed, so when I run my app, it have to fire immediately.

NSTimeInterval roundedInterval = round([[NSDate date] timeIntervalSinceReferenceDate] / 60.0) * 60.0 + 60; // the extra 60 is used to set the correct time Interval between next minute and referenced date.
NSDate *date = [NSDate dateWithTimeIntervalSinceReferenceDate:roundedInterval];

Now, it's working!


Solution

  • The key is to start that recurring timer at the right time. Get the current time and find out how many seconds we are into the current minute...

    NSDateComponents *components = [[NSCalendar currentCalendar] components: NSSecondCalendarUnit fromDate:[NSDate date]];
    NSInteger second = [components second];
    

    From this we can get the number of seconds until the next minute...

    NSInteger tillNextMinute = (60 - second) % 60;
    

    I haven't tested that, but the idea of the mod 60 is to handle the case when second is zero. Now we're almost done...

    [self performSelector:@selector(startTimer) withObject:nil afterDelay:tillNextMinute];
    

    Then the code you began with...

    - (void)startTimer {
        // contains the code you posted to start the timer
    }