1

I am trying to change a UIButton's UIImage every second, until a counter reaches 0. I have tried NSTimer, performSelector withDelay but I could not get either of those to work, plenty of googling came up with different options but pointed to the fact I can't update the UI when in a for or while loop, or when an NSTimer is running.

The code below gets me close, the logs show execution is pausing for one second and the imageName is correct....but the button image does not change.

Any help greatly appreciated.

- (void)setTimerCountdownImage {

  NSString *imageWithTime = @"recordTimer";
  UIImage *btnImage = [UIImage imageNamed:@"recordTimer.png"];

  if (_timerDelay != 0) {

    NSLog(@"Timer Delay is:%d", _timerDelay);
    btnImage = [UIImage imageNamed:[[imageWithTime stringByAppendingString:[NSString stringWithFormat:@"%d", _timerDelay]] stringByAppendingString:@".png"]];
    NSLog(@"TimerImage is: %@",[[imageWithTime stringByAppendingString:[NSString stringWithFormat:@"%d", _timerDelay]] stringByAppendingString:@".png"]);
    [_toggleTimerBtn setImage:btnImage forState:UIControlStateNormal];
    [self countDownTimer:_timerDelay];
 
  }
  else {
   [_toggleTimerBtn setImage:btnImage forState:UIControlStateNormal];
  }
}

-(void)countDownTimer:(int) currentDelay {
 _timerDelay = _timerDelay -1;
 NSLog(@"Time to sleep...");
 [NSThread sleepForTimeInterval:1.0];
 [self setTimerCountdownImage];
}

Output from logs:

2015-02-17 01:42:22.357 SwingPlane[299:16789] Timer Delay is:5
2015-02-17 01:42:22.358 SwingPlane[299:16789] TimerImage is: recordTimer5.png
2015-02-17 01:42:22.358 SwingPlane[299:16789] Time to sleep...
2015-02-17 01:42:23.360 SwingPlane[299:16789] Timer Delay is:4
2015-02-17 01:42:23.374 SwingPlane[299:16789] TimerImage is: recordTimer4.png
2015-02-17 01:42:23.375 SwingPlane[299:16789] Time to sleep...
2015-02-17 01:42:24.377 SwingPlane[299:16789] Timer Delay is:3
2015-02-17 01:42:24.391 SwingPlane[299:16789] TimerImage is: recordTimer3.png
2015-02-17 01:42:24.392 SwingPlane[299:16789] Time to sleep...
2015-02-17 01:42:25.394 SwingPlane[299:16789] Timer Delay is:2
2015-02-17 01:42:25.408 SwingPlane[299:16789] TimerImage is: recordTimer2.png
2015-02-17 01:42:25.408 SwingPlane[299:16789] Time to sleep...
2015-02-17 01:42:26.411 SwingPlane[299:16789] Timer Delay is:1
2015-02-17 01:42:26.427 SwingPlane[299:16789] TimerImage is: recordTimer1.png
2015-02-17 01:42:26.428 SwingPlane[299:16789] Time to sleep...

zaph
  • 111,848
  • 21
  • 189
  • 228
guytz72
  • 419
  • 2
  • 14
  • 1
    Try forcing the UI update to happen on the main thread by wrapping the UI updates in a dispatch_async(dispatch_get_main_queue(), ^{ }); block. – Lyndsey Scott Feb 17 '15 at 02:15
  • 1
    Forget you ever knew that there was such a thing as sleep. It is a VERY BAD IDEA for a device like an iPhone. You want to use an NSTimer, as Raspu suggests. It's very easy. – Duncan C Feb 17 '15 at 02:33

1 Answers1

1

Remember to make all UI changes on the main thread. And use a NSTimer! try this (I didn't run it myself, let me know if it doesn't work):

- (void)startTimerWithDelay:(NSInteger)delay {

    _timerDelay = delay;
    _timer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(setTimerCountdownImage) userInfo:nil repeats:YES];

}


- (void)setTimerCountdownImage {

    NSString *imageWithTime = @"recordTimer";
    UIImage *btnImage = [UIImage imageNamed:@"recordTimer.png"];

    _timerDelay--;

    if (_timerDelay != 0) {

        btnImage = [UIImage imageNamed:[[imageWithTime stringByAppendingString:[NSString stringWithFormat:@"%d", _timerDelay]] stringByAppendingString:@".png"]];
    } else {

        [_timer invalidate];
    }

    dispatch_async(dispatch_get_main_queue(), ^{
        [_toggleTimerBtn setImage:btnImage forState:UIControlStateNormal];
    });
}

Remember to add NSTimer *_timer to the class or it won't work.

JP Illanes
  • 3,665
  • 39
  • 56
  • Perfect thanks. I actually need the main execution to wait for the time interval too, but I called [self performSelector:theSelector withObject:nil afterDelay:_timerDelay]; ...after that worked like a charm. – guytz72 Feb 17 '15 at 20:09
  • Awesome, glad to be helpful. – JP Illanes Feb 18 '15 at 00:38