问题
我正在构建一个应用程序,我将获取实时数据并更新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];
}
});
}
答案 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];
}