NSTimer not firing in modal panel

I have a repeating timer installed like this:

_cmdTimer = [NSTimer timerWithTimeInterval: 0.5
        target: self
        selector: @selector(timedTask:)
        userInfo: nil
        repeats: YES];
[NSRunLoop.mainRunLoop addTimer: _cmdTimer
                    forMode: NSModalPanelRunLoopMode];
[NSRunLoop.mainRunLoop addTimer: _cmdTimer
                    forMode: NSDefaultRunLoopMode];

The first time the timer fires, it opens a modal dialog. But then the timer does not fire again until the dialog is closed. I don't get that, since I scheduled the timer in NSModalPanelRunLoopMode. To verify that the dialog was running in that mode, just before opening the dialog I said

[self performSelector: @selector(testMe)
        withObject: nil
        afterDelay: 0.7
        inModes: @[NSModalPanelRunLoopMode] ];

and the testMe method did get executed while the dialog was open.

Accepted Reply

The first time the timer fires, it opens a modal dialog.

Yeah, that’s not going to work. Your run loop source hasn’t run to completion, so it never gets reactivated.

I recommend that you use a different timer, creating it before presenting the modal and invalidating it when the modal ends.

Also, consider scheduling it in the common modes. If you’re not up to speed on that see WWDC 2010 Session 207 Run Loops Section.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Replies

The first time the timer fires, it opens a modal dialog.

Yeah, that’s not going to work. Your run loop source hasn’t run to completion, so it never gets reactivated.

I recommend that you use a different timer, creating it before presenting the modal and invalidating it when the modal ends.

Also, consider scheduling it in the common modes. If you’re not up to speed on that see WWDC 2010 Session 207 Run Loops Section.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

@eskimo Thanks! What I ended up doing is using a delayed perform (which, I gather, uses another timer behind the scenes) to run the dialog. Then my timer fires both inside and outside the dialog.