NSTimer重复得太快了

时间:2014-08-01 03:01:19

标签: ios7 mkmapview nstimer mkannotationview

问题

我正在构建一个应用程序,我将获取实时数据并更新MKMapView。我每10秒获得一批数据,并且在来自Web服务的数据集之间,我正在删除旧数据点,同时还添加新数据点。

我不想一次性更新它们,而是希望在10秒内分散我从数据服务获得的新点的动画,这样我就可以创建“实时”的感觉并避免尽可能多的停止和启动。

除了NSTimer总是尽早完成之前,一切似乎都很有效。它应该在10秒内循环遍历新数据,但它通常会提前4到5秒完成新数据集的循环。

我已阅读了很多Apple文档和StackOverflow问题(以下是可能正在寻找的两个好问题):)

https://stackoverflow.com/a/18584973 https://developer.apple.com/library/ios/technotes/tn2169/_index.html#//apple_ref/doc/uid/DTS40013172-CH1-TNTAG8000

但似乎大部分建议是针对使用CADisplayLink的游戏应用程序(但我没有构建游戏应用程序),或者如果您需要使用高性能计时器,则不应连续使用。

我的计时器不需要精确,但如果我甚至可以在.5秒内得到它,那将是很好的,而不必添加我见过的其他一些选项的开销。

一如既往,您可以指出我的任何想法/代码/指示将不胜感激。

代码

一旦我将新数据收集到数组中,我就会创建时间间隔并使用下面的代码启动计时器

addCount = -1;
timerDelay = 10.0/[timerAdditions count];

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

然后通过添加和删除我的地图注释激发此动画方法。

-(void) delayMethod {

addCount = addCount +1;

if (addCount >= [timerAdditions count]) {

    [timerRemovals removeAllObjects];
    [timerAdditions removeAllObjects];
    addCount = -1;
    [delayTimer invalidate];
    delayTimer = nil;

} else  {


    [myMap addAnnotation:[timerAdditions objectAtIndex:addCount]];
    [myMap removeAnnotation:[timerRemovals objectAtIndex:addCount]animated:YES];

}

}

更新

我尝试通过GCD更新我的计时器。奇怪的是,定时循环适用于所有其他数据集。仍然没有它每个领带工作,但由于某种原因它似乎与重置调度时间或计时器间隔有关。

 -(void) delayMethod {

dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * timerDelay); // How long
dispatch_after(delay, dispatch_get_main_queue(), ^(void){

    addCount = addCount +1;

    if (addCount >= [timerAdditions count]) {

        [timerRemovals removeAllObjects];
        [timerAdditions removeAllObjects];
        addCount = -1;
        //[delayTimer invalidate];
        //delayTimer = nil;

    } else  {

        NSLog(@"Delay fired count %i -- additoins %lu",addCount,(unsigned long)[timerAdditions count]);

        [myMap addAnnotation:[timerAdditions objectAtIndex:addCount]];
        [myMap removeAnnotation:[timerRemovals objectAtIndex:addCount]animated:YES];
        [self delayMethod];

    }

});


}

2 个答案:

答案 0 :(得分:0)

我正在使用这样的计时器来处理计时器实例,以获得更准确的结果。

- (void)createTimer {
    // start timer
    if(gameTimer == nil)
        gameTimer = [NSTimer timerWithTimeInterval:1.00 target:self selector:@selector(timerFired:) userInfo:nil repeats:YES] ;
    [[NSRunLoop currentRunLoop] addTimer:gameTimer forMode:NSDefaultRunLoopMode];
    timeCount = 725; // instance variable or you can set it as your need
}
- (void)timerFired:(NSTimer *)timer {
    // update label
    if(timeCount == 0){
        [self timerExpired];
    } else {
        timeCount--;
        if(timeCount == 0) {
            // display correct dialog with button
            [timer invalidate];
            [self timerExpired];
        }
    }
    //do your stuff here for particular time.
}
- (void) timerExpired {
    // display an alert or something when the timer expires.
    NSLog(@"Your time is over");
    [gameTimer invalidate];
    gameTimer = nil;

    //do your stuff for completion of time.
}

在你想要的这段时间间隔内。并根据需要增加递减量。然后用定时器触发并完成。在你的情况下,如果你不想让计时器到期而不是ok。永远不会使计时器实例无效,只使用计时器触发事件​​来做事。

答案 1 :(得分:0)

由于我在下面引用的另一个SO问题,我走了一条略有不同的道路。基本上通过将两个定时器组合成一个,将一个定时器设置为我需要的最快时间间隔,并且在定时器调用的方法中管理我需要的方法,我已经解决了我所看到的问题。

https://stackoverflow.com/a/25087473/2939977

timeAdder = (10.0/[timerAdditions count]);
timeCountAnimate = timeAdder;
[NSTimer scheduledTimerWithTimeInterval:0.11 target:self selector:@selector(timerFired) userInfo:nil repeats:YES];




- (void)timerFired {

timeCount += 0.111;

if (timeCount > 10.0) {

    // call a method to start a new fetch
    timeCount = 0.0;
    timeCountAnimate =0.0;
    [self timerTest];

}

if (timeCount > timeCountAnimate) {

    timeCountAnimate += timeAdder;
     [self delayMethod];

}