这个问题可能已经存在,但我找不到它。我的问题基本上就是这个。如果我有一个重复的NSTimer执行一些比定时器间隔更长的东西,会不会有一些颠簸会让应用程序崩溃?或者,新的时间事件是否在正在执行的任务完成之前才开始?
答案 0 :(得分:2)
由于NSTimer在运行循环上运行,因此它创建了,我认为它不能重新输入它调用的方法。这个document on the run loops证实了这一点(参见“计时器来源”部分:
“同样,如果计时器在运行循环处于中间时触发 执行处理程序例程,计时器等到下一次 通过运行循环来调用其处理程序例程“
答案 1 :(得分:1)
您始终只需安排一次仅出现一次的定时器,然后在该功能完成时重新安排它。
- (void)myFunction {
......stuff that your method does
[NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(myFunction) userInfo:nil repeats:NO];
}
答案 2 :(得分:0)
重复计时器总是根据计划的点火时间来计划自己,而不是实际点火时间。例如,如果计划在特定时间和之后每5秒计时一次计时器,则计划的点火时间将始终落在原始的5秒时间间隔上,即使实际点火时间延迟。如果射击时间延迟到目前为止它通过一个或多个预定的射击时间,则计时器仅在该时间段内被触发一次;然后,计时器在射击后重新安排,用于将来的下一个预定射击时间。
答案 3 :(得分:0)
只要你避免开始一些异步工作,你就没事了。如果异步调度任务通常需要的时间超过计时器调用之间的间隔,那么该队列可以得到备份。如果正在制作动画,即使动画可能无法完成,计时器也会启动。
让我举两个例子。对于这两个例子,让我们假设我们创建一个每秒触发一次的计时器:
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(handleTimer:)
userInfo:@"tick"
repeats:YES];
第一个例子:我们假设我们有一些串行队列:
self.queue = [[NSOperationQueue alloc] init];
self.queue.maxConcurrentOperationCount = 1;
此外,我们假设我们有一个NSTimer
处理程序,它可以执行以下操作:
- (void)handleTimer:(NSTimer *)timer
{
NSLog(@"%s %@", __FUNCTION__, timer.userInfo);
[self.queue addOperationWithBlock:^{
NSLog(@"%s starting some slow process; has %d operations queued", __FUNCTION__, self.queue.operationCount);
// to simulate a slow process, let's just sleep for 10 seconds
sleep(10);
NSLog(@"%s done", __FUNCTION__);
}];
}
因为计时器每秒都会触发,并且因为计时器处理程序几乎立即返回(因为它正在进行的所有操作都在排队后台操作),所以当第一个排队操作(需要10秒)完成并且第二个排队操作开始时,已经有10个操作位于该后台队列中。当第二次后台操作完成时,当第三次操作开始时,有19个操作排队。它只会变得更糟,因为NSTimer
处理程序将继续被调用,比较慢的后台操作被清除出队列更快。显然,如果处理程序在当前队列中同步执行了所有操作,那么一切都很好,并且没有积压,NSTimer
没有“捶打”。
第二个例子:此问题的另一个例子是动画。让我们假设计时器处理程序方法正在执行类似下面的操作:启动一个移动UIImageView
的10秒动画:
- (void)handleTimer:(NSTimer *)timer
{
NSLog(@"%s %@", __FUNCTION__, timer.userInfo);
[UIView animateWithDuration:10.0
animations:^{
self.imageView.frame = [self determineNewFrame];
}
completion:nil];
}
这不起作用(或者更确切地说,即使前一个动画没有完成,你也会看到定时器调用handleTimer
的后续调用)。如果你要这样做,你必须跟踪动画是否完成。你必须做类似的事情:
- (void)handleTimer:(NSTimer *)timer
{
NSLog(@"%s %@", __FUNCTION__, timer.userInfo);
if (!self.animating)
{
NSLog(@"%s initiating another animation", __FUNCTION__);
[UIView animateWithDuration:10.0
animations:^{
self.animating = YES;
self.imageView.frame = [self determineNewFrame];
}
completion:^(BOOL finished){
self.animating = NO;
}];
}
}
你要么必须做一些状态标志(比如我的布尔animation
标志),以防止在第一个完成之前有额外的动画,或者只是不使用定期计时器,只需启动{{1中的另一个计时器completion
动画类方法的块。