我有一个NSTimer
以 3 秒的间隔触发以减小值的方法。当我执行增加该值的操作时,我想重新启动计时器以从该点开始计数 3 秒。
例如,如果我增加值并且计时器将在 1 秒内触发,我想更改它并让计时器在 3 秒内触发。我可以使计时器无效并重新创建它吗?或者我可以setFireDate:
使用当前日期并添加 3 秒的间隔来执行此操作吗?
我有一个NSTimer
以 3 秒的间隔触发以减小值的方法。当我执行增加该值的操作时,我想重新启动计时器以从该点开始计数 3 秒。
例如,如果我增加值并且计时器将在 1 秒内触发,我想更改它并让计时器在 3 秒内触发。我可以使计时器无效并重新创建它吗?或者我可以setFireDate:
使用当前日期并添加 3 秒的间隔来执行此操作吗?
是的,您可以使其无效。并再次创建它。
您还可以使用:
- (void) myTimedTask {
// other stuff this task needs to do
// change the variable varyingDelay to be 1s or 3s or... This can be an instance variable or global that is changed by other parts of your app
// weStillWantTimer is also a similar variable that your app uses to stop this recurring task
if (weStillWantTimer)
[self performSelector:@selector(myTimedTask:) withObject:gameColor afterDelay:varyingDelay];
}
您调用 myTimedTask 来启动循环任务。启动后,您可以使用 varyingDelay 更改延迟或使用 weStillWantTimer 停止它。
我做了一些测试,结果证明重置 fireDate 比无效和重新创建计时器快四倍。首先,我创建一个调用方法 doNothing 的计时器:
if (!testTimer) {
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3.0
target:self
selector:@selector(doNothing:)
userInfo:nil
repeats:NO];
testTimer = timer;
}
这是测试代码:
- (void) testInvalidatingTimer {
for (int n = 0; n < 10000; n++) {
[testTimer invalidate];
testTimer = nil;
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:3.0
target:self
selector:@selector(doNothing:)
userInfo:nil
repeats:NO];
testTimer = timer;
}
}
- (void) testResettingTimer {
for (int n = 0; n < 10000; n++) {
if ([testTimer isValid]) {
testTimer.fireDate = [NSDate dateWithTimeIntervalSinceNow:3.0];
}
}
}
在 iPad Air 上运行该程序会产生 0.198173 秒的无效定时器和 0.044207 秒的重置定时器。如果性能是您的目标,我建议重置 fireDate。它的编码工作量也少了很多。
使计时器无效并重新创建它。但是,请确保您不会使计时器无效并释放,除非您确定需要这样做,因为运行循环会保留计时器,直到它们无效,然后自行释放它们。
在我看来,将 -performSelector 代码与计时器代码混合会导致目标方法的多次执行,所以我会远离它。
是的,使计时器无效并重新创建将起作用。如果您不增加价值,这基本上就是您想要做的:重置并重新开始。
文档提到更改触发日期相对昂贵,这setFireDate:
表明最好销毁并重新创建计时器,除非您经常这样做。然而,为了争论,我不久前就提出了这个类别。我更喜欢这个,因为它封装了日期调整行为;计时器本身处理它,而不是它的所有者/控制器。不过,我没有这方面的任何性能数据。
@implementation NSTimer (WSSAdjustingFireDate)
- (void)WSSFireAdjustingFireDate
{
[self fire];
[self WSSSkipNextFireAdjustingFireDate];
}
- (void)WSSSkipNextFireAdjustingFireDate
{
CFRunLoopTimerRef cfSelf = (__bridge CFRunLoopTimerRef)self;
CFTimeInterval delay = CFRunLoopTimerGetInterval(cfSelf);
CFRunLoopTimerSetNextFireDate(cfSelf, CFAbsoluteTimeGetCurrent() + delay);
}
@end
我使用 Core Foundation 函数只是为了避免创建NSDate
. 过早优化?请把盐递过去。