Must remove submenu when dealloccing NSMenuItem?
Must remove submenu when dealloccing NSMenuItem?
- Subject: Must remove submenu when dealloccing NSMenuItem?
- From: Jerry Krinock <email@hidden>
- Date: Wed, 21 Feb 2007 19:03:17 -0800
- Thread-topic: Must remove submenu when dealloccing NSMenuItem?
I had subclassed NSMenu to make hierarchical contextual menus attached to
cells in NSOutlineViews, following [1]. While troubleshooting some
occasional crashes a few weeks ago, I saw reports indicating messages
possibly sent to contextual menus/items that had disappeared a long time
ago. To study this, in my NSMenu subclass I placed NSLog statements in the
-init and -dealloc methods.
RESULT: As a hierarchical contextual menu was displayed and traversed, in
the log I saw subclassed NSMenu objects being initted as they appeared.
After the mouse was released and the menu disappeared, I saw that the
top-level objects were deallocced, but the deeper objects were never
deallocced, even after the parent outline, window and document were closed
and deallocced.
SOLUTION: I added code to send -setSubmenu:nil to each item of my NSMenus as
they are being deallocced [2]. Now, all the nested NSMenus are always
deallocced when the menu disappears.
CONCLUSION: I think this indicates a leak in Apple's implementation of
NSMenuItem; possibly that they retain the _submenu as an instance variable,
but don't set it to nil during -dealloc. Either that, or they've got a
retain cycle. Methods -[NSMenuItem menu] and -[NSMenu supermenu], which
refer to what I'd call their "parents" and "grandparents" respectively, have
always worried me a little.
Unfortunately, I can't reproduce the crashes now, but seeing that log of
perfectly matching inits and deallocs sure looks makes me feel a lot better.
Does anyone disagree that this indicates a leak/bug in NSMenuItem?
Jerry Krinock
1. http://developer.apple.com/releasenotes/Cocoa/AppKitOlderNotes.html
Search for text "populate a menu just before it is going to be drawn".
2. Fix is to subclass NSMenu, and override -dealloc.
- (void)removeSubmenusFromAllItems {
int lastIndex = [[self itemArray] count] - 1 ;
int i ;
for (i=lastIndex; i>=0; i--) {
NSMenuItem* item = [self itemAtIndex:i] ;
[item setSubmenu:nil] ;
}
}
- (void) dealloc {
[self removeSubmenusFromAllItems] ;
[self setDelegate:nil] ;
// No experiments on the above; I just think it is
// a good practice to setDelegate:nil in -dealloc
[super dealloc];
}
I suppose that if you had happened to subclass NSMenuItem for some reason,
it would be easier. You could simply override its -dealloc, inserting
[self setSubmenu:nil] ;
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden