Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using NSTimer to implement retry logic with exponential backoff

I'm trying to implement retry logic with exponential backoff using NSTimer. My code looks like this:

-(void)start
{
  [NSTimer scheduledTimerWithTimeInterval:0.0 target:self
    selector:@selector(startWithTimer:) userInfo:nil repeats:NO];
}

-(void)startWithTimer:(NSTimer *)timer
{
  if (!data.ready) {
    // timer.timeInterval == 0.0 ALWAYS!
    NSTimeInterval newInterval = timer.timeInterval >= 0.1 ? timer.timeInterval * 2 : 0.1;
    newInterval = MIN(60.0, newInterval);
    NSLog(@"Data provider not ready. Will try again in %f seconds.", newInterval);
    NSTimer * startTimer = [NSTimer scheduledTimerWithTimeInterval:newInterval target:self
        selector:@selector(startWithTimer:) userInfo:nil repeats:NO];
    // startTimer.timeInteval == 0.0 ALWAYS!
    return;
  }

  ...
}

The problem I'm having is that the timer NSTimer scheduledTimerWithTimeInterval seems to ignore the interval I'm providing and always sets it to 0.0. Any suggestions on what I'm doing wrong here?

like image 689
Ivan Avatar asked Apr 23 '12 04:04

Ivan


1 Answers

The Apple Documentation has this to say about the timeInterval property on NSTimer.

https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nstimer_Class/Reference/NSTimer.html

If the receiver is a non-repeating timer, returns 0 (even if a time interval was set).

You will need to use some other means to keep track of what the timer interval should be. I recommend an iVar on your class.

-(void)start
{
  _timeInterval = 0.0;
  [NSTimer scheduledTimerWithTimeInterval:_timeInterval target:self
    selector:@selector(startWithTimer:) userInfo:nil repeats:NO];
}

-(void)startWithTimer:(NSTimer *)timer
{
  if (!data.ready) {
    _timeInterval = _timeInterval >= 0.1 ? _timeInterval * 2 : 0.1;
    _timeInterval = MIN(60.0, _timeInterval);
    NSLog(@"Data provider not ready. Will try again in %f seconds.", _timeInterval);
    NSTimer * startTimer = [NSTimer scheduledTimerWithTimeInterval:_timeInterval target:self
        selector:@selector(startWithTimer:) userInfo:nil repeats:NO];
    return;
  }

  ...
}
like image 178
Tim Reddy Avatar answered Oct 12 '22 23:10

Tim Reddy