Changing fireDate of a repeating NSTimer

2019-07-26 04:51发布

问题:

I am building an app where I need to stack to two timed events (one within the other). I have one timer that will call a web service every 10 seconds and get new data. Between the web service calls I will animate each object I receive over 10 seconds (to bridge the gap and create a 'real-time' feel).

The amount of data I am receiving from the web service will vary and thus my animation timer needs to vary to space out the animations out over 10 seconds.

I am trying to change the timeInterval of my repeating NSTimer but can not get it to change the timeinterval when the next data set comes in.

timerDelay = 9.8/([timerAdditions count]-1);

if (!delayTimer) {

    delayTimer =[NSTimer scheduledTimerWithTimeInterval:timerDelay target:self selector:@selector(delayMethod) userInfo:nil repeats:YES];
    [[NSRunLoop mainRunLoop] addTimer:delayTimer forMode:NSRunLoopCommonModes];

} else {

    NSTimeInterval timeInMiliseconds = timerDelay;
    NSDate *myDate =[NSDate dateWithTimeIntervalSinceNow:timeInMiliseconds];
    delayTimer.fireDate = myDate;


}

回答1:

The best way I've found to coordinate two timers is to have just one timer, used as a pulse. I would do something like this:

// keep state on when the next fetch should happen
@property(strong,nonatomic) NSDate *fetchTime;

// keep state on how much animation to do per tick
@property(assign,nonatomic) NSInteger mapPointsPerFrame;

// run a single timer at the highest frame-rate you'll need
NSTimer *timer =[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES];

- (void)timerFired:(NSTimer *)timer {

    // is it time to do a fetch?
    NSDate *now = [NSDate date];
    if ([self.fetchTime laterDate:now] == self.fetchTime) {
        // call a method to start a new fetch
        self.fetchTime = [NSDate dateWithTimeInterval:10 sinceDate:now];
    }

    // either way, do animations if they are needed
    NSInteger mapPoints = self.mapPointsPerFrame;
    while (self.mapPointsToAnimate.count && mapPoints) {
        // call a method to add a map point
        mapPoints--;
    }
}

The only thing left to do is to set self.mapPointsPerFrame. Do that after each fetch. If your frame interval is 0.5s and you fetch every 10s, then the equation for that looks like this:

// just fetched N things and added N objects to self.mapPointsToAnimate
// try to animate them all by the next fetch
self.mapPointsPerFrame = (self.mapPointsToAnimate.count / 20) + 0.5; // 0.5 to round