【问题标题】:Change NSTimer interval for repeating timer更改重复计时器的 NSTimer 间隔
【发布时间】:2010-06-09 09:29:58
【问题描述】:

我在 Cocoa 中使用 NSTimer 运行一个 mainLoop,如下所示:

        mainLoopTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/fps target:self selector:@selector(mainloop) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:mainLoopTimer forMode:NSEventTrackingRunLoopMode];

在程序启动时,我将 timeInterval 设置为 0.0,以便主循环尽可能快地运行。无论如何,我想提供一个函数来在运行时将帧速率(以及计时器的时间间隔)设置为特定值。不幸的是,据我所知,这意味着我必须重新初始化计时器,因为 Cocoa 不提供像“setTimerInterval”这样的功能 这是我尝试过的:

    - (void)setFrameRate:(float)aFps
{
    NSLog(@"setFrameRate");
    [mainLoopTimer invalidate];
    mainLoopTimer = nil;

    mainLoopTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/aFps target:self selector:@selector(mainloop) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:mainLoopTimer forMode:NSEventTrackingRunLoopMode];
}

但这会引发以下错误并停止主循环:

2010-06-09 11:14:15.868 myTarget[7313:a0f] setFrameRate 2010-06-09 11:14:15.868 myTarget[7313:a0f] * __NSAutoreleaseNoPool(): __NSCFDate 类的对象 0x40cd80 自动释放,没有适当的池 - 只是泄漏 2010-06-09 11:14:15.869 myTarget[7313:a0f] * __NSAutoreleaseNoPool(): NSCFTimer 类的对象 0x40e700 自动释放,没有适当的池 - 只是泄漏 0.614628

我还尝试使用“retain”关键字重新创建计时器,但这并没有改变任何东西。 关于如何在运行时动态更改 NSTimer 的时间间隔的任何想法?

谢谢!

【问题讨论】:

    标签: cocoa macos timer


    【解决方案1】:

    我知道,这个帖子太老了! 但我也在寻找功能!

    事实证明,NSTimes 不提供此功能,因此我决定自己构建一个。 这不是最好的解决方案,但就我而言,这是唯一可能的。

    我定义了变量“BOOL keepOn;”在我的标题中。

    -(IBAction)doSomething:(id)sender
    {
        // Any action to throw every interval.
    }
    
    -(IBAction)switchAutoLoad:(id)sender
    {
        if([autoLoad state] == NSOffState)
        {
            NSLog(@"auto-reload on!");
    
            self performSelector:@selector(fireTimer) withObject:nil afterDelay:0];
            keepOn = YES;
            [autoLoad setState:NSOnState];
        }
        else
        {
            NSLog(@"auto-reload off!");
            keepOn = NO;
            [autoLoad setState:NSOffState];
        }
    }
    
    -(void)fireTimer
    {
        [self doSomething:nil];
    
        float theTime = 20; // This is the time interval.
    
        if(keepOn)
        {
            [self performSelector:@selector(fireTimer) withObject:nil afterDelay:theTime];
        }
    }
    

    (非常)之二的问题是,“计时器”正在等待整个延迟,然后才能获得新值。 你看,它没有快速响应:)) 而且您不能立即停止它(必须等待延迟完成)。

    如果你停止它,它会按预期再抛出一个动作。

    实际上它适用于我,适用于小应用程序和工具。

    【讨论】:

      【解决方案2】:

      你不应该释放 mainLoopTimer。
      当您创建它时,您会收到一个自动释放的实例,并且运行循环会保留对该实例的引用。
      当你从循环中移除它时它会被释放:如果你手动释放它,它会被删除并且运行循环会尝试访问一个无效的对象。
      这就是它崩溃的原因。

      编辑: 我完全误读了,我以为我在无效时看到了释放,对不起。 问题似乎是没有 AutoreleasePool 到位。 这通常在 main() 中完成:首先创建自动释放池

      NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
      

      并在退出 main 之前释放它。

      查看 here 获取自动释放池文档。

      【讨论】:

      • 我应该怎么做才能改变间隔?
      • 请见谅。我误读了 [mainLoopTimer 版本]。您对计时器的操作正确,但似乎没有 AutoReleasePool 到位。看看这里:developer.apple.com/mac/library/documentation/cocoa/conceptual/…
      • 嗯,我已经尝试过安装自动释放池,但没有成功,但我会再试一次!
      • 好的,如果我放置一个自动释放池,并像这样初始化计时器: mainLoopTimer = [[NSTimer scheduledTimerWithTimeInterval:fps target:self selector:@selector(mainloop) userInfo:nil repeats:YES]自动释放];它不会抛出泄漏错误,但应用程序会被中断。还有其他想法吗?
      • 不,只是 GDB:中断,我很确定问题是我覆盖了计时器。没有其他方法可以设置间隔吗?
      【解决方案3】:

      您可以尝试取消注册以前的计时器并以不同的频率启动新的计时器。 您可以通过

      取消注册
      [yourOldTimer invalidate];
      yourOldTimer = nil;
      

      这或许能解决问题。

      【讨论】:

      • 如您所见,我已经这样做了,但它不起作用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多