0

I'm going to describe my scenario:

I have a UIViewController that is always loaded whenever a user signs in the app because it manages an UIView that is always shown once the user is logged in. This UIView disappears when the user logs out. This UIViewController has a @property (strong, nonatomic) NSTimer *timer; declared. I want this timer to show the user a countdown that may take several minutes long. This timer should start whenever the UIView is shown and restarts its counting for every 20 secs in order to refresh the countdown displayed each 20 secs until it reaches 0:

-(void)start
{
   if (self.timer != nil) {
      [self.timer invalidate];
       self.timer = nil;
   }

   // Some operations here
   self.countdown = untilTime;    // countdown total secs

   self.timer = [NSTimer scheduledTimerWithTimeInterval:20
                                                  target:self
                                                selector:@selector(notifyTimerTick:)
                                                userInfo:nil
                                                 repeats:YES];
}

- (void)notifyTimerTick:(NSTimer *)timer
{
   self.countdown -= 20;

   if (self.countdown <= 0) {
    [self start];
   }

   [self updateCountdown];    // Countdown label shown to user
}

That is, whenever the countdown reaches 0, a new countdown starts again for N minutes depending on certain operations I perform in -(void)start method. And this scenario should keep working as long as the user is logged in the app.

In AppDelegate, I stop this timer when the app becomes inactive or goes to background (or user logs out):

- (void)applicationWillResignActive:(UIApplication *)application
{
   if (isUserLogged) {
      [self.countdownViewController stopTimer];
   }
}

- (void)applicationDidEnterBackground:(UIApplication *)application
{
   if (isUserLogged) {
      [self.countdownViewController stopTimer];
   }
}

Where stopTimer method is this:

- (void)stopTimer
{
   if (self.timer != nil) {
      [self.timer invalidate];
      self.timer = nil;
   }
}

I start again the timer in applicationDidBecomeActive: method by calling -(void)start method I already described, method that I also call when the user logs in the app.

This is working for me the 95% of times, but I've found in a couple of times during testing that sometimes the countdown goes faster than it should. I mean, for example: if countdown should take 6 min, it took more or less 3 min to reach the 0 value the last time I saw this weird effect, and the countdown shown to user was updating faster as well. It was like there were more than one timer performing the countdown, but I don't understand why, because it is usually working fine and I don't find what circumstances are causing this.

I found this fast countdown while testing a beta version of the app in a real iOS 7 device. When I wanted to see what was happening, and I connected the device to Xcode and Instruments, the app launching caused the timer working fine again, so I couldn't debug nor see anything in 'Instruments' of this scenario.

I think I'm managing the timer correctly, am I missing something? Has somebody experienced something like this? I've read some posts about releasing timers, but they only say that you have to invalidate the timer and I'm already doing it:

Releasing an NSTimer iPhone?

Correct way to release NSTimer?

I need help to analyze this issue. Thanks a lot in advance

EDIT: Does my code ensure that only one NSTimer object can be running? Should I manage something related to the timer in dealloc method?

Community
  • 1
  • 1
AppsDev
  • 12,319
  • 23
  • 93
  • 186
  • if is redundant in your start method – Andrey Chernukha Jul 23 '14 at 06:44
  • @AndreyChernukha if it is the first time I call the method and the property is nil, I don't need to invalidate and "nillify" it... right? – AppsDev Jul 23 '14 at 06:49
  • no, i don't mean you don't need invalidating. you just don't need to check if it's nil or not because it doesn't matter – Andrey Chernukha Jul 23 '14 at 06:53
  • `NSTimer` is a pain, so I would have it running all the time, once-per-second, but only count the "ticks" under the conditions you want and ignore them at other times. – trojanfoe Jul 23 '14 at 06:55
  • @trojanfoe the point is that I don't know what is happening, because when I want to debug, the countdown works ok again... so I don't know what conditions should I take into account. Since th speed of the countdown is increased, I've thought that it may be caused because somehow I get at least two timers running, but looking at my code I'm not sure if that is possible... – AppsDev Jul 23 '14 at 07:27
  • Have you considered just using CoreAnimation? – quellish Jul 24 '14 at 06:25

0 Answers0