NSViews, timers, and visibility

I’m running into a stumbling block with Cocoa, and after spending an hour searching through documentation and not finding an answer I figure I’ll post it here and see if anyone reading this knows the answer. Bear in mind that I’m unfortunately not much of a Cocoa programmer.

I have a custom view (a subclass of NSView) with a timer that updates something in the view. The view only needs to be updated when it’s visible, and it’s visible whenever its window is visible. How do I stop the timer when its window is hidden or closed and start the timer again when the window is shown?

5 Comments

  1. Mike Said,

    November 7, 2004 @ 1:00 am

    There are a few options. You can tell the timer to constantly reschedule itself (repeat) or you can manually init a new timer firing each time your scheduled message gets called.

    However, I think maybe you are asking the wrong question. My impression is that you want to use the timer to update your data model and let the system figure out when it needs redrawing. Basically, this means your scheduled message doesn’t actually do any drawing, but it may call setNeedsDisplay: at the end. I believe that if your view is offscreen/obscured, you will not see any calls to your views drawRect routine as a result of that call, however as soon as is necessary, it will be called.

    I’ve been having a hell of a time working on an animated image ticker view using timers – it works very efficiently most of the time, but achieving truly smooth, consistent motion has proved extremely difficult (can’t iron out the occasional timing hiccups).

  2. Eric Albert Said,

    November 7, 2004 @ 5:05 am

    Calls to -drawRect: aren’t the problem. I’m trying to get the application to take no CPU time when no windows are showing, but it’s currently using a small amount of the CPU because the timer keeps running when the window is hidden.

  3. Chris Hanson Said,

    November 7, 2004 @ 5:06 am

    Mike is on the right track: Have your timer update an attribute of the view, and let that send the view -setNeedsDisplayInRect: for the affected rectangle.

    To keep track of when the window containing the view isn’t visible, you can subscribe to various NSWindow notifications or implement a delegate for your window. Useful notifications might be NSWindowDidChangeScreenNotification, NSWindowDidExposeNotification, NSWindowDidMiniaturizeNotification, NSWindowDidMoveNotification, and NSWindowWillCloseNotification. You’ll probably also want to subscribe to notifications like NSApplicationDidHideNotification and NSApplicationDidUnhideNotification.

  4. Mike Said,

    November 7, 2004 @ 11:48 am

    If that be your quest, then I think you will have to do a [timer invalidate] when you detect that your application has been hidden. The notifications mentioned are a good start. Now, from my reading of the documentation, if you have called [NSTimer scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:] to set up the timer, the invalidate call will remove the timer from the current run loop and have the added side effect of releasing the only retain on the timer object itself. There is some dispute about that, but that’s my reading.

  5. Greg Parker Said,

    November 8, 2004 @ 10:43 am

    Your view (or an appropriate controller) can listen for notifications from the window and the application, and start or stop the timer appropriately. Interesting notifications include:

    NSApplicationWillBecomeActive/WillResignActiveNotification: note when the application is in front
    NSApplicationWillHide/WillUnhideNotification: note when the application is hidden
    NSWindowWillCloseNotification: note when the window is closed
    NSWindowWillMiniaturize/DidDeminiaturizeNotification: note when window is sent to the Dock

RSS feed for comments on this post

google