Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change NSTimer interval for repeating timer

Tags:

macos

cocoa

timer

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!

like image 277
moka Avatar asked Nov 15 '22 10:11

moka


1 Answers

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.

like image 121
Julian F. Weinert Avatar answered Dec 26 '22 11:12

Julian F. Weinert