Reputation: 1191
I am writing a Cocoa OpenGL app and running my main loop with a CVDisplayLink
per this technical note. It works fine for running the loop.
The problem is that sometimes when I quit, my display link callback will be called on its own thread after my application has already quit. This causes my rendering code to get called and crash as soon as I call any OpenGL function (glClear
in this case), because my context no longer exists.
I have CVDisplayLinkRelease(displayLink);
in my NSView's dealloc
function, but it never seems to get called, I'm assuming because of ARC. Is there someway I can ensure that my display link is destroyed before my view?
Edit: I didn't notice the crash is actually being triggered by an assert I have. I assert on glGetError
after each OpenGL call I make to make sure I can catch bugs early. After a call to glClear
or [[view openGLContext] flushBuffer];
I get error 1286, which is GL_INVALID_FRAMEBUFFER_OPERATION
.
That makes logical sense because my window and thus view are being deallocated, but it doesn't help the problem. I don't want to just ignore those errors because they could obviously happen in more cases than just this. I still need to find the "right" way to ensure my display link is shut down before my view.
Upvotes: 3
Views: 1557
Reputation: 96373
When an application terminates, nothing in its autorelease pool gets released—the application simply exit
s and lets the operating system clean up the memory. Since nothing gets released, nothing receives a dealloc
message.
This means two things:
There are two ways to handle termination. The way I usually do it in a single-window app is by having my application's delegate be nothing else, and directly own my primary window controller. The other way is to add yourself as an observer for the NSApplicationWillTerminate
notification and respond to it by, e.g., stopping your display link.
If any part of your cleanup may take some time, your application's delegate should respond to applicationShouldTerminate:
by returning NSTerminateLater
, and you should send the application a replyToApplicationShouldTerminate:
message when you're done with whatever you needed to do.
The other solution to the original problem—your CVDisplayLink callback getting called before you have a chance to close the link—is the complete opposite: Enable sudden termination. When that is enabled, your application will quit by sending itself SIGKILL
(better known by the command-line invocation kill -9
), which means that every one of your threads will stop immediately.
Of course, if you have anything that really does need to be cleaned up (lock files, network connections, etc.), then you should disable sudden termination around those things' lifetime, and be prepared for regular termination during that time.
Upvotes: 3