I recently converted my AudioUnit plugin to take advantage of ARC for all the interface code (Cocoa). However, this resulted in the main NSView (the one created by the CocoaViewFactory and returned to the plugin as a property) never having -dealloc called. This made it impossible to dispose of the AUEventListener constructed for the NSView - which is documented to cause crashes - and creates a tonne of memory leaks (none of the Objective-C objects retained by the NSView are deallocated, either).
I 'solved' the problem by compiling only the CocoaViewFactory.m file without ARC, and returning the NSView at the end of -(NSView*)uiViewForAudioUnit with an autorelease. NSView -dealloc is now called when the window is closed, and memory is cleaned up as expected.
I'm a little unsure of myself with memory management, so am worried that this solution is going to cause some other memory bug. I can't find any documents that use ARC for the Cocoa code as a basis to work from. Does anyone have any ideas or experience with this?
EDIT: The non-ARC version of the CocoaViewFactory.m file is :
- (NSView *)uiViewForAudioUnit:(AudioUnit)inAU withSize:(NSSize)inPreferredSize {
if (! [NSBundle loadNibNamed: @"PluginName_CocoaView" owner:self]) {
NSLog (@"Unable to load nib for view.");
return nil;
}
[uiFreshlyLoadedView setAU:inAU];
NSView *returnView = uiFreshlyLoadedView;
uiFreshlyLoadedView = nil; // zero out pointer. This is a view factory. Once a view's been created
// and handed off, the factory keeps no record of it.
return [returnView autorelease];
}
The uiFreshlyLoadedView
variable is declared in CocoaViewFactory.h like so:
@interface PluginName_CocoaViewFactory : NSObject <AUCocoaUIBase>
{
IBOutlet PlugingName_CocoaView * uiFreshlyLoadedView;
}
It is not a property, it is bound directly to the NSView in the XIB file.
The only change I made when attempting to build this as ARC was to replace the final line in the .m file with:
return returnView;
figuring that the AudioUnit process that called this method would create its own copy of the returnView
, and it would be released when the scope of this method ends. Using this line, and compiling as ARC, the NSView is never deallocated.
However, thinking about it now as I write, I realise that the AudioUnit calling code is not Obj-C, it's all C++, and I wasn't bridging the returned view in any meaningful way.