将NSTimer的射击时间重置为从现在开始而不是最后一次射击

时间:2009-10-17 17:33:04

标签: objective-c cocoa-touch nstimer

我有NSTimer以3秒的间隔触发以减少值。当我执行一个增加该值的操作时,我想重新启动计时器,从那时起计算3秒钟。

例如,如果我增加值并且计时器将在1秒内触发,我想改变它并使计时器在3秒内激活。我可以使计时器无效并再次创建吗?或者我可以使用setFireDate:,使用当前日期并添加3秒的间隔吗?

5 个答案:

答案 0 :(得分:7)

是的,您可以使其无效。并再次创建它。

您也可以使用:

- (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来启动定期任务。一旦启动,您可以使用varyDelay更改延迟或使用weStillWantTimer将其停止。

答案 1 :(得分:3)

我做了一些测试,结果发现重置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秒用于invalidatingTimer和0.044207秒用于resettingTimer。如果性能是您的目标,我建议重置fireDate。它的编码工作量也相当少。

答案 2 :(得分:1)

使计时器无效并重新创建它。但是,请确保不要使释放计时器失效,除非您确定需要,因为运行循环会保留计时器,直到它们失效,然后自行释放它们。

在我看来,将-performSelector代码与定时器代码混合会导致目标方法的多次执行,所以我会远离它。

答案 3 :(得分:1)

是的,无效并重新创建计时器将起作用。如果你没有增加价值,它本质上就是你想要做的事情:重置并重新开始。

答案 4 :(得分:1)

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。过早优化?请传盐。