更改重复定时器的NSTimer间隔

5

我正在使用类似这样设置的NSTimer在Cocoa中运行一个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():对象0x40cd80的类__NSCFDate在没有放置池子的情况下被自动释放,只是泄漏了。 2010-06-09 11:14:15.869 myTarget[7313:a0f] *__NSAutoreleaseNoPool():对象0x40e700的类NSCFTimer在没有放置池子的情况下被自动释放,只是泄漏了。 0.614628
我还尝试使用“retain”关键字重新创建计时器,但是那并没有改变任何东西。有没有关于如何在运行时动态更改NSTimer间隔的想法?
谢谢!
3个回答

3

我知道,这个帖子已经非常老了! 但我也在寻找这种功能!

事实证明,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];
    }
}

非常大的问题是,“计时器”需要等待整个延迟时间才能获取新值。

你看,它反应不够快:)

而且你不能立即停止它(必须等待延迟完成)。

如果你停止它,它会执行一个额外的操作。

对于我的小应用和工具来说,实际上这种方式可以工作并且还不错。


0

你不应该释放mainLoopTimer。
当你创建它时,你收到了一个自动释放的实例,并且runloop保持对该实例的引用。
只有当你从循环中删除它时,它才会被释放:如果你手动释放它,它就会被删除,而runloop尝试访问一个无效的对象。
这就是为什么它会崩溃。

编辑: 我完全误读了,我以为看到的是release,但实际上是invalidate,抱歉。 问题似乎是没有放置AutoreleasePool。 通常在main()中完成:将autorelease pool作为第一件事创建

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

在 main 函数退出之前释放它。

请查看这里的自动释放池文档。


我应该做什么来改变时间间隔? - moka
请原谅我。我误读了[mainLoopTimer release]。 您对计时器的操作是正确的,但似乎没有放置自动释放池。请参考这里:http://developer.apple.com/mac/library/documentation/cocoa/conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html - garph0
嗯,我已经尝试过放置自动释放池,但是没有起作用,不过我会再试一次! - moka
好的,如果我放置一个自动释放池,并像这样初始化计时器: mainLoopTimer = [[NSTimer scheduledTimerWithTimeInterval:fps target:self selector:@selector(mainloop) userInfo:nil repeats:YES] autorelease]; 它不会抛出泄漏错误,但应用程序会被中断。还有其他想法吗? - moka
我用主循环中的performSelector调用替换了计时器,现在一切都正常了,除了performSelector似乎不准确,因为它无法达到我告诉它的FPS,总是比我设定的慢几个FPS(例如,只有57而不是60,或者只有114而不是120),你有什么想法吗? - moka
显示剩余2条评论

-2

你可以尝试注销先前的计时器,并以不同的频率启动新的计时器。 您可以通过以下方式注销:

[yourOldTimer invalidate];
yourOldTimer = nil;

这可能解决问题。


正如您所看到的,这是我已经做过的,但它并不起作用。 - moka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接