【问题标题】:Double the amount of time until NSTimer's fireDateNSTimer 的 fireDate 之前的时间加倍
【发布时间】:2014-03-08 22:37:33
【问题描述】:

我正在使用NSTimer,在某些情况下,我希望在调用NSTimer 方法之前加倍。

基本上:如果我将它设置为每 0.5 秒调用一次,我想偶尔延迟它,以便在下次调用之前等待 1.0 秒(时间的两倍)。

但是,我在实现这一点时遇到了很大的困难。这是我最初的尝试:

- (void)viewDidLoad
{
    [super viewDidLoad];

    [NSTimer scheduledTimerWithTimeInterval:0.5 
                                     target:self 
                                   selector:@selector(timerMethod:) 
                                   userInfo:nil 
                                    repeats:YES];
}

- (void)timerMethod:(NSTimer *)timer {
    static int variable = 1;

    switch (variable) {
        case 1:
            self.stopLightLabel.textColor = [UIColor redColor];
            break;
        case 2:
            self.stopLightLabel.textColor = [UIColor orangeColor];
            break;
        case 3:
            self.stopLightLabel.textColor = [UIColor yellowColor];
            break;
        case 4: // Stop for twice as long here
            self.stopLightLabel.textColor = [UIColor greenColor];

            NSTimeInterval timeBetweenNowAndFireDate = [timer.fireDate timeIntervalSinceNow];

            // Create a new date that is twice as far in the future in order to give a long pause
            timer.fireDate = [NSDate dateWithTimeIntervalSinceNow:(timeBetweenNowAndFireDate * 2)];

            break;
        case 5:
            self.stopLightLabel.textColor = [UIColor blueColor];
            break;
        case 6:
            self.stopLightLabel.textColor = [UIColor purpleColor];
            break;
        default:
            break;
    }

    variable++;
}

我尝试获取现在与计时器何时触发之间的时间量。在上面的示例中,这应该是0.5。然后我将fireDate 设置为一个新值,是之前的两倍。

但是,这不起作用。

如果没有这个条件,计时器可以正常工作,但显然不会在某种情况下延迟(在这种情况下,它得到的时间与其他所有情况相同)。

有了条件,它甚至显得更短!事实上,直到我将它乘以大约 400 而不是 2,它才变得更长!

我在这里做错了什么?

【问题讨论】:

  • 为什么不直接将条件添加到被调用的选择器来决定是否运行,然后您根本不必摆弄计时器
  • 您在调试时看到的时间间隔的实际值是多少?
  • 你什么时候做这个 :) 请给我们看更多代码
  • @Paul.s 因为fireDate 实例变量正是为此目的而创建的...
  • @Daij-Djan 这是一个完整的项目:cl.ly/0q0L3R2X2E3y

标签: ios objective-c cocoa-touch nstimer


【解决方案1】:

您调用代码来修改 timerFired 方法中的 fireDate。那还为时过早。 fireDate 是计时器在那里触发的日期。它还没有更新。

一个简单的解决方法:将其包装在异步调度中。让计时器在您尝试修改它之前返回并更新其 fireDate:

固定代码:

- (void)timerMethod:(NSTimer *)timer {
    static int variable = 1;

    dispatch_async(dispatch_get_main_queue(), ^{
        [self afterTimerFired:timer];
    }
 }

- (void)afterTimerFired:(NSTimer *)timer {
    static int variable = 1;        
        switch (variable) {

            case 4: // Stop for twice as long here
                self.stopLightLabel.textColor = [UIColor greenColor];
                ...
                NSTimeInterval timeBetweenNowAndFireDate = [timer.fireDate timeIntervalSinceNow];
                NSLog(@"%f", timeBetweenNowAndFireDate);
                // Create a new date that is twice as far in the future in order to give a long pause
                timer.fireDate = [NSDate dateWithTimeIntervalSinceNow:(timeBetweenNowAndFireDate * 2)];
                ...

不要调度 async 和 make fireDate = [NSDate dateWithTimeIntervalSinceNow:fire.timeInterval*2] 如果可能的话,它可能会更干净

【讨论】:

  • 或者不调度异步并让 fireDate = [NSDate dateWithTimeIntervalSinceNow:fire.timeInterval*2]
  • 我不同意,因为它完全可以预测。我在 runloop 的下一次迭代中移动我的代码——与 performSelector:afterDelay:0 相同是完全可预测的并且经常使用:)——dispatch_after 会引入一些随机延迟会很糟糕
  • 我不反对它会起作用,但我总是会经历额外的痛苦以确保这是唯一的解决方案,然后再添加延迟以使某些东西起作用。
  • 是的,DELAY 很糟糕,因为它感觉就像是 hack .. 但我并没有真正添加延迟,我总是在当前方法调用之后移动它。
  • 这是一个延迟,因为您将执行延迟到下一个运行循环。但是仔细思考这个问题似乎是最简单的方法
【解决方案2】:

我很确定您不能更改正在运行的计时器的 fireDate。 (这是错误的。请参阅下面的编辑。)

另一张海报 Paul.s 的想法与我相同。如果您有一个每 0.5 秒触发一次的计时器,请将 BOOL skipThisInterval 实例变量添加到作为计时器目标的对象。

然后,在您的计时器方法中,如果skipThisInterval 为真,只需重置skipThisinterval = FALSE 并返回而不执行任何其他操作。这样,计时器将在另一个时间间隔过后再次触发,然后像以前一样继续运行。

如果做不到这一点,您将不得不使正在运行的计时器无效,创建一个将在您希望的结束时间触发一次的新计时器,然后在计时器调用的方法中,创建一个新的重复计时器,该计时器将返回到触发时间旧间隔。

编辑:我错了。您可以更改“飞行中”计时器的触发日期。 (感谢 Josh Caswell 对此的纠正。)

即使如此,如果您只是希望您的计时器简单地跳过它的下一次触发并继续运行,只需向计时器调用的方法添加逻辑以跳过下一次触发似乎比调整 fireDate 更简单、更清晰(文档说更改开火日期相对昂贵。)

【讨论】:

  • 您确实可以将fireDate 更改为预定的计时器。文档说“您通常使用这种方法来调整重复计时器的触发时间。”
  • 这就是fireDate 的全部意义所在,所以我正在尝试使用它。
  • @JoshCaswell,我的错。谢谢你纠正我。我学到了一些东西。这将教会我基于假设而不是检查文档来发布。 (投票)
  • @DuncanC 我们可能没有阅读相同的文档 ^^ 修改 fireDate 比扔掉并重新创建计时器更好
  • @Daij-Djan,我不建议扔掉计时器。我建议编写一个计时器方法,该方法简单地忽略一次计时器的触发并让计时器继续运行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多