Search code examples
iosobjective-cmultithreadinguilabelcountdown

iOS: UILabel countdown hangs on other UI operation


I'm implementing a countdown with its value displayed on a UILabel, but have run into a problem. Here's the simplified code:

self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countdown) userInfo:nil repeats:YES];

- (void)countdown {          
     self.countdownLabel.text = [NSString stringWithFormat:@"%i",[self.countdownLabel.text intValue]-1];

     // Handle time out
     if ([self.countdownLabel.text intValue] == 0) {
             [self.countdownTimer invalidate];
             self.countdownTimer = nil;
     }
}

It works fine, but if I do other UI operations in the viewcontroller, like scroll a scrollview, the timer hangs as the scrollview scrolls and then boosts up to make up for the idle moments.

I tried dispatching the updating of the label to a background queue which of course didn't work.

dispatch_queue_t bgQ = dispatch_queue_create("bgQ", 0);
dispatch_async(bgQ, ^{
    self.countdownLabel.text = [NSString stringWithFormat:@"%i",[self.countdownLabel.text intValue]-1];
});

What would be the solution here?


Solution

  • self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(countdown) userInfo:nil repeats:YES];    
    [[NSRunLoop mainRunLoop] addTimer:self.countdownTimer forMode:NSRunLoopCommonModes];
    

    Remember that in your countdown method you need an escape to invalidate your countdownTimer.

    The timer will start without fire instruction when the

    [[NSRunLoop mainRunLoop] addTimer:self.countdownTimer forMode:NSRunLoopCommonModes];
    

    line is executed. ABSOLUTELY no dispatch async for UI changes.

    Hope this helps.