I have a Cocoa plug-in that is loaded into an existing Carbon application.
When the plug-in is first loaded, the Carbon application calls an initialization function, Plugin_Init()
and in that function I set up the environment like so:
//this is the global autorelease pool
static NSAutoreleasePool* globalPool = nil;
void Plugin_Init()
{
NSApplicationLoad(); //loads the Cocoa event loop etc
//create an autorelease pool
globalPool=[[NSAutoreleasePool alloc] init];
//callback functions are registered here
Plugin_defineFunction("doSomething",doSomething,0);
}
However, the Carbon app does not send any notifications when the application is about to terminate.
Is it actually necessary to clean up the "global" autorelease pool that I've created when the app terminates?
I tried registering for the Carbon app quit event by adding a call to the registerForApplicationQuitNotification()
function below, but when the application terminated I received warnings that I was calling -release
on an invalid autorelease pool. Is there a problem with how I'm handling the Carbon events?
//handles the Carbon application quit notification
static pascal OSStatus handleApplicationQuitEvent(EventHandlerCallRef nextHandler, EventRef evt, void *ud)开发者_StackOverflow社区
{
OSStatus err = noErr;
UInt32 evtkind;
evtkind = GetEventKind( evt );
if ( evtkind == kEventAppQuit )
{
//release the global autorelease pool
[globalPool release];
}
// call the rest of the handlers
err = CallNextEventHandler( nextHandler, evt);
return err;
}
//registers for the Carbon application quit notification
void registerForApplicationQuitNotification()
{
// install an event handler to tear down some globals on Quit
static EventHandlerUPP app = NULL;
EventTypeSpec list[] = {
{kEventClassApplication, kEventAppQuit},
};
app = NewEventHandlerUPP( handleApplicationQuitEvent );
if (!app)
return;
InstallApplicationEventHandler(app, GetEventTypeCount(list), list, NULL, NULL);
}
It's quite likely that NSApplicationLoad
sets up NSApplication's first autorelease pool, which will be below yours in the autorelease pool stack (since it was created first). In the background, it will drain this pool and create a new one as it needs to; the first time this happens, your pool goes away, since it was above Cocoa's pool in the stack.
The simple solution is to cut out your global pool and let NSApplication create it. An alternative would be to create and drain local pools within each handler function, particularly if you don't actually need anything from the Application Kit in your plug-in.
If the autorelease pool is the only cleanup you need to do, then no, you don't need to register for a quit notification. Any pool you create is still within the application's address space, which will be freed by the OS when the process terminates.
Also, autorelease pools are typically created per-thread. If your callbacks invoked on different threads, you may need to create a pool per thread. Note that Cocoa also needs to be told that it's operating in a multithreaded environment; see the Threads section of the NSAutoreleasePool reference.
精彩评论