• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Must remove submenu when dealloccing NSMenuItem?
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Must remove submenu when dealloccing NSMenuItem?


  • Subject: Re: Must remove submenu when dealloccing NSMenuItem?
  • From: Jerry Krinock <email@hidden>
  • Date: Wed, 21 Feb 2007 21:39:12 -0800
  • Thread-topic: Must remove submenu when dealloccing NSMenuItem?

on 07/02/21 20:34, stephen joseph butler at email@hidden wrote:

> Can you post some code for how you create these submenus?

Surely.  Here you go!!

If anyone's interested, there's a lot more where this came from :)

By the way, in my original post I forgot to mention that the telltale
function that I saw in the stack trace of those crash reports a few weeks
ago was "HIToolbox PopulateMenu()".

*******************************************************************
Method in subclass of NSOutlineView which gives contextual menu:
*******************************************************************
- (NSMenu*)menuForTableColumnIndex:(int)iCol rowIndex:(int)iRow {
    // Snipped out processing of iCol and iRow to get item
    // and other local variables derived from item

    NSMenu* menu = [[NSMenu allocWithZone:[NSMenu menuZone]]
         initWithTitle:@""];

    // Temporary variables which will be used while adding Menu Items
    NSMenuItem* menuItem ;
    SEL action ;
    NSMenu* bookmarksHierarchicalMenu ; // Used in Copy To

    _beLazy = NO ;

    // Now, add menu items

    // Snipped out adding several menu items

    // Add Menu item "Copy to ->"
    menuItem = [[NSMenuItem allocWithZone:[NSMenu menuZone]]
        initWithTitle:NSLocalizedString(@"Copy to", nil)
               action:nil
        keyEquivalent:@""];
    bookmarksHierarchicalMenu = [[SSMenu alloc]
            initWithOwningMenuItem:menuItem] ;
    // Note: owningMenuItem is a convenience, so I don't have to
    // use -supermenu and then enumerate through its -itemArray.
    // So as not to create a retain cycle, it is a "weak reference";
    // it is ^not^ retained by SSMenu
    [menuItem setSubmenu:bookmarksHierarchicalMenu] ;
    [bookmarksHierarchicalMenu setDelegate:
         [self bookmarksHierarchicalMenuDataSource]] ;
    // The above is an instance of MenuOutlineDataSource, see below.
    // In -awakeFromNib, it is initWithHost:self
    // That is, this outline view is what I call the "host" of the
    // MenuOutlineDataSource.  (It's a weak reference, not retained)
    [bookmarksHierarchicalMenu release] ;
    [menuItem setTag:2] ;
    [menu addItem:menuItem];
    [menuItem release];

    // Snipped out adding additional menu items

    // Snipped out releases of other local variables

    return [menu autorelease] ;
}

*******************************************************************
Class: SSMenu
*******************************************************************

@interface SSMenu : NSMenu {

    id _owningMenuItem ; // the NSMenuItem which this object is the submenu
of
                         // weak reference, to avoid retain cycles
}

// Snipped declarations

@end

@implementation SSMenu

- (void)setOwningMenuItem_Weakly:(id)x {
    // Weak reference.  Not retained, to avoid retain cycle
    _owningMenuItem = x ;
}

- (id)owningMenuItem {
    return _owningMenuItem ;
}

- (void)removeSubmenusFromAllItems {
    int lastIndex = [[self itemArray] count] - 1 ;
    int i ;
    for (i=lastIndex; i>=0; i--) {
        NSMenuItem* item = [self itemAtIndex:i] ;
        [item setSubmenu:nil] ;
    }
}

- (id)initWithOwningMenuItem:(id)owningMenuItem {
    self = [super init];
    if (self != nil) {
        [self setOwningMenuItem_Weakly:owningMenuItem] ;
    }
    return self;
}

- (void) dealloc {
    [self removeSubmenusFromAllItems] ;
    [self setDelegate:nil] ;

    [super dealloc];
}

- (id)retain {
    return [super retain] ;
}

- (void)release {
    [super release] ;
}

@end

*******************************************************************
Protocol: SSHierarchicalMenuHost
*******************************************************************

@protocol SSHierarchicalMenuHost

- (BOOL)beLazy ;
// For explanation of beLazy, see:
// http://www.cocoabuilder.com/archive/message/cocoa/2006/7/20/168013
- (NSArray*)selectedObjects ;

@end

*******************************************************************
Class: MenuOutlineDataSource
*******************************************************************

// A Data Source which provides delegate methods
// to build a hierarchical bookmarks menu

#import "SSApp/SSHierarchicalMenuHost.h"

@interface MenuOutlineDataSource : NSObject {

    id _host ; // Weak reference, not retained, to avoid retain cycle

}

- (id) initWithHost:(id <SSHierarchicalMenuHost>)host ;

@end

@implementation MenuOutlineDataSource

- (void)setHost_Weakly:(id)host {
    // Weak reference.  Not retained, to avoid retain cycle
    _host = host ;
}

- (id)host {
    return _host ;
}

- (IBAction)abortBecauseCopyNotAllowed:(id)sender {
    NSBeep() ;
    [[NSApp delegate] alertCannotCopy] ;
}

- (IBAction)abortBecauseMoveNotAllowed:(id)sender {
    NSBeep() ;
}

- (IBAction)moveOrCopySelectionToSender:(id)sender  {
    BmItem* targetFolder = [sender representedObject] ;
    int tag = 0 ;
    NSMenuItem* ancestor = sender ;

    // Go up the menu hierarchy until a tag is found, to indicate
    // whether this came from the Move To or Copy To menuItem
    while (tag == 0) {
        ancestor = [(SSMenu*)[ancestor menu] owningMenuItem] ;
        tag = [ancestor tag] ;
    }

    enum SSParentingAction action ;
    if (tag == 1) {
        action = SSParentingMove ;
    }
    else {
        action = SSParentingCopy ;
    }

    [[NSApp delegate] parentingAction:action
                                items:[[self host] selectedObjects]
                            toParents:targetFolder
                            atIndexes:[NSNumber numberWithInt:0]] ;
}

- (int)numberOfItemsInMenu:(SSMenu*)menu {
    int answer ;
    if ([[self host] beLazy]) {
        answer = 0 ;
    }
    else {
        BmItem* itemRepresentedByMenu = [[menu owningMenuItem]
representedObject] ;

        if (!itemRepresentedByMenu) {
            // root item
            answer =
                 [[[NSDocumentController sharedDocumentController]
                            bookmarksDocuments] count] ;
        }
        else {
            // not root item
            answer = [itemRepresentedByMenu numberOfSubfolders] ;
        }
    }

    return answer ;

}

- (BOOL)menu:(SSMenu*)menu
  updateItem:(NSMenuItem*)item
     atIndex:(int)index
shouldCancel:(BOOL)shouldCancel {
    BOOL answer ;
    id <SSHierarchicalMenuHost> host = [self host] ;
    if ([host beLazy]) {
        answer = NO ;
    }
    else {
        BmItem* itemRepresentedByMenu =
              [[menu owningMenuItem] representedObject] ;

        NSString* title ;
        id rawRepresentedItem ;
        BmItem* cookedRepresentedItem ;

        if (!itemRepresentedByMenu) {
            // itemRepresentedByMenu is a root
            rawRepresentedItem =
                 [[[NSDocumentController sharedDocumentController]
                       bookmarksDocuments] objectAtIndex:index] ;
            title = [rawRepresentedItem displayName] ;
            cookedRepresentedItem = [rawRepresentedItem root] ;
        }
        else {
            // itemRepresentedByMenu is not a root
            rawRepresentedItem =
               [[itemRepresentedByMenu subfolders] objectAtIndex:index] ;
            title = [rawRepresentedItem name] ;
            cookedRepresentedItem = rawRepresentedItem ;
        }

        [item setRepresentedObject:cookedRepresentedItem] ;
        [item setTitle:title] ;
        [item setTarget:self] ;

        // Set action depending on whether the drop proposed move/copy is OK
        // Note: If I setEnabled:NO, this grays it out, and the triangle
still
        // appears on the right, but unfortunately the submenu does not
appear
        // I wish I could have a grayed out menu item with a working
submenu,
        // but Cocoa does not seem to support this.  So I leave it always
        // enabled and set the action to do explain and/or beep after item
        // is clicked.
        NSArray* proposedPayload = [host selectedObjects] ;
        if (![[NSApp delegate] checkOkToCopyItems:proposedPayload]) {
            [item setAction:@selector(abortBecauseCopyNotAllowed:)] ;
        }
        else if (![[NSApp delegate] checkOKToInsertItems:proposedPayload
                                      atBmLocation:
                     [BmLocation BmLocationWithParent:
                     cookedRepresentedItem index:0]]) {
            [item setAction:@selector(abortBecauseMoveNotAllowed:)] ;
        }
        else {
            [item setAction:@selector(moveOrCopySelectionToSender:)] ;
        }

        if ([cookedRepresentedItem numberOfSubfolders] > 0) {
            // Create and add a submenu to item
            SSMenu* submenu = [[SSMenu alloc] initWithOwningMenuItem:item] ;
            [submenu setDelegate:self] ;
            [item setSubmenu:submenu] ;
            [submenu release] ;
        }

        answer = YES ;
    }

    // If you return NO, it does not come back and ask to update any
    // more items, so you can end up with "empty" menu items if the menu
    // is actually shown
    return answer ;
}

- (id)initWithHost:(id <SSHierarchicalMenuHost>)host {
    if (self = [super init]) {
        [self setHost_Weakly:host] ;
    }
    return self;
}


@end


_______________________________________________

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

  • Follow-Ups:
    • Re: Must remove submenu when dealloccing NSMenuItem?
      • From: Michael Nickerson <email@hidden>
    • Re: Must remove submenu when dealloccing NSMenuItem?
      • From: "stephen joseph butler" <email@hidden>
References: 
 >Re: Must remove submenu when dealloccing NSMenuItem? (From: "stephen joseph butler" <email@hidden>)

  • Prev by Date: Re: Must remove submenu when dealloccing NSMenuItem?
  • Next by Date: Re: Must remove submenu when dealloccing NSMenuItem?
  • Previous by thread: Re: Must remove submenu when dealloccing NSMenuItem?
  • Next by thread: Re: Must remove submenu when dealloccing NSMenuItem?
  • Index(es):
    • Date
    • Thread