更改重复计时器的 NSTimer 间隔

发布于 2024-09-04 11:07:31 字数 1314 浏览 4 评论 0原文

我正在 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 的间隔有什么想法吗?

谢谢!

I am running a mainLoop in Cocoa using an NSTimer set up like this:

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

At Program startup I set the timeInterval to 0.0 so that the mainloop runs as fast as possible. Anyways, I would like to provide a function to set the framerate(and thus the time interval of the timer) to a specific value at runtime. Unfortunately as far as I know that means that I have to reinitialize the timer since Cocoa does not provide a function like "setTimerInterval"
This is what I tried:

    - (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];
}

but this throws the following error and stops the mainloop:

2010-06-09 11:14:15.868 myTarget[7313:a0f] setFrameRate
2010-06-09 11:14:15.868 myTarget[7313:a0f] * __NSAutoreleaseNoPool(): Object 0x40cd80 of class __NSCFDate autoreleased with no pool in place - just leaking
2010-06-09 11:14:15.869 myTarget[7313:a0f] *
__NSAutoreleaseNoPool(): Object 0x40e700 of class NSCFTimer autoreleased with no pool in place - just leaking
0.614628

I also tried to recreate the timer using the "retain" keyword, but that didn't change anything.
Any ideas about how to dynamically change the interval of an NSTimer at runtime?

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

中二柚 2024-09-11 11:07:31

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

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

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

如果你停止它,它会按照预期再执行一项操作。

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

I know, this thread is amazing old!
But I was in search of the functionality too!

As it turned out, that the NSTimes doesn't provide this feature, I decided to build an own one.
It's not the best solution, but in my case it was the only possible.

I defined the variable "BOOL keepOn;" in my header.

-(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];
    }
}

The (very) bis issue is, that the "timer" is waiting the whole delay, before it can get a new value.
You see, it's not responding fast :))
And you can't stop it immediately (have to wait for the delay to finish).

And if you stop it, it's throwing one more action as supposed.

Actually it works for my and is ok for little apps and tools.

酒废 2024-09-11 11:07:31

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

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

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

,并在退出 main 之前释放它。

查看这里了解 Autorelease池文档。

You should not release mainLoopTimer.

When you created it, you received an autoreleased instance, and the runloop is keeping the reference to that instance.
It will be released when you remove it from the loop: if you manually release it, it gets deleted and the runloop tries to access an invalid object.
That's why it crashes.

EDIT:
I totally misread and I thought I saw release when it was an invalidate, sorry.
The problem seems to be that there is no AutoreleasePool in place.
This is usually done in main(): create the autorelease pool as the first thing

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

and release it just before exiting from main.

Have a look here for Autorelease pools documentation.

仅一夜美梦 2024-09-11 11:07:31

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

[yourOldTimer invalidate];
yourOldTimer = nil;

这可能会解决目的。

You can try un-register previous timer and start new one with different frequency.
you can un-register by

[yourOldTimer invalidate];
yourOldTimer = nil;

This might solve the purpose.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文