Question

Compiling in XCode 3.1.1 for OSX 10.5.8 target, 32-bit and i386 build.

I have a modal run loop, running in NSWindow wloop and NSView vloop. The modal loop is started first. It starts, runs and stops as expected. Here's the start:

[NSApp runModalForWindow: wloop];

Then, when the user presses the left mouse button, I do this:

if (ticking == 0) // ticking is set to zero in its definition, so starts that way
{
    ticking = 1; // don't want to do this more than once per loop
    tickCounter = 0;
    cuckCoo = [NSTimer scheduledTimerWithTimeInterval: 1.0f / 10.0f         // 10x per second
                                               target: self                 // method is here in masterView
                                             selector: @selector(onTick:)   // method
                                             userInfo: nil                  // not used
                                              repeats: YES];                // should repeat
}

Checking the return of the call, I do get a timer object, and can confirm that the timer call is made when I expect it to be.

Now, according to the docs, the resulting NSTimer, stored globally as "cuckCoo", should be added to the current run loop automagically. The current run loop is definitely the modal one - at this time other windows are locked out and only the window with the intended mouse action is taking messages.

The method that this calls, "onTick", is very simple (because I can't get it to fire), located in the vloop NSView code, which is where all of this is going on:

- (void) onTick:(NSTimer*)theTimer
{
    tickCounter += 1;
    NSLog(@"Timer started");
}

Then when it's time to stop the modal loop (which works fine, btw), I do this:

[cuckCoo invalidate];
[NSApp stop: nil];
ticking=0;
cuckCoo = NULL;
NSLog(@"tickCounter=%ld",tickCounter);

ticking and tickCounter are both global longs.

I don't get the NSLog message from within onTick, and tickCounter remains at zero as reported by the NSLog at the close of the runloop.

All this compiles and runs fine. I just never get any ticks. I'm at a complete loss. Any ideas, anyone?

Was it helpful?

Solution 2

The answer specific to...

[NSApp runModalForWindow: wloop];

...is, after the modal run loop has been entered:

NSRunLoop *crl;

    cuckCoo = [NSTimer timerWithTimeInterval: 1.0 / 10
                                      target: self
                                    selector: @selector(onTick:)
                                    userInfo: nil
                                     repeats:YES];
    crl = [NSRunLoop currentRunLoop];
    [crl addTimer: cuckCoo forMode: NSModalPanelRunLoopMode];

(crl obtained separately for clarity) Where the onTick method has the form:

- (void) onTick:(NSTimer*)theTimer
{
    // do something tick-tocky
}

OTHER TIPS

The problem is related to this statement "The current run loop is definitely the modal one". In Cocoa, each thread has at most one runloop, and each runloop can be run in a variety of "modes". Typical modes are default, event tracking, and modal. Default is the mode the loop normally runs in, while event tracking is typically used to track a drag session of the mouse, and modal is used for things like modal panels.

When you invoke -[NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:] it does schedule the timer immediately, but it only schedules it for the default runloop mode, not the modal runloop mode. The idea behind this is that the app generally shouldn't continue to run behind a modal panel.

To create a timer that fires during a modal runloop, you can use -[NSTimer initWithFireDate:interval:target:selector:userInfo:repeats:] and then -[NSRunLoop addTimer:forMode:].

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top