views:

122

answers:

1

My app has two views, one holds the OpenGL context which is constantly redrawing itself (through an NSTimer) and the other holds a picker wheel. While I'm spinning the wheel, it seems that the timer stops firing. Is there some method I could override for the picker view to manually call the draw? Or some way to keep the timer firing?

Thanks, -S

+1  A: 

Your timer is not firing because it was created on the main thread. User interface interactions also occur on that main thread, so when you are working with the picker or something else processing touch events, your timer will be blocked from firing.

One way to handle this is to create a separate thread which acts as a timer. An example of the kind of method you could use for this would be

- (void)openGLUpdateThread;
{
    while (!isOpenGLUpdateCancelled)
    {
     [self updateOpenGLView];

     // Do this at 30 FPS
     [NSThread sleepForTimeInterval:(1.0f / 30.0f)];
    }
}

You then perform this on a background thread using

[NSThread detachNewThreadSelector:@selector(openGLUpdateThread) toTarget:self withObject:nil];

I believe that you can update the display of an OpenGL layer on a background thread with no problems, as long as it's not being accessed by another thread, but if you run into crashes, you can do just the display updates on the main thread using

[self performSelectorOnMainThread:@selector(updateOpenGLView) withObject:nil waitUntilDone:NO];

instead of the straight call to -updateOpenGLView in the thread method above.

To kill the thread, just set your isOpenGLUpdateCancelled instance variable to NO and wait a bit for it to finish. Of course, all of the methods and instance variables here are just examples and would need to be changed to meet your application.

Brad Larson
This worked! I have a couple issues though...I would like to use the first method you suggested ([NSThread detachNewThreadSelector:@selector(openGLUpdateThread) toTarget:self withObject:nil];) but my openGL calls are hopelessly entangled with the rest of the code and it would be annoying to separate them all so that they are all on the same thread. The second method (performSelectorOnMainThread) works, but then my touch events losing priority to the view update so I get weird interface functionality. Is there some way I can ensure that the touch events have a higher priority? Thanks!
spencewah
Everything called in the updateOpenGLView method that gets called above will run on the same thread, unless you specify otherwise via a performSelectorOnMainThread or the like. Therefore, even if you have a bunch of other methods that help to generate, manipulate, or display your geometry, as long as they're called from that one method they'll be in the same thread.
Brad Larson
That said, if your OpenGL updates are slow enough that putting them on the main thread messes up your touch response times, placing them on a background thread may not give you that much of a performance win on a single-core machine like the iPhone. It might be time to do some hardcore Instruments and Shark tuning of your display code.
Brad Larson