small medium large xlarge

Generic-user-small
02 Feb 2011, 13:34
Ric Levy (21 posts)

Hi Tim,

I took up your challenge to find a way of validating the “Remove Item From Shopping List” menu item, and after much head-scratching and poring through docs, came up with this:

- (BOOL)validateUserInterfaceItem:(id < NSValidatedUserInterfaceItem >)anItem
{
	if (([anItem action] == @selector(removeItemFromShoppingList:)) && ([shoppingListTableView selectedRow] == -1))
		return NO;
	else
		return YES;
	
	 return [super validateUserInterfaceItem:anItem];
}

</code>

When I downloaded your solution, I found that it is slightly different:

- (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
    
    // we're only interested in validating the removeItem... action
    if ([menuItem action] == @selector(removeItemFromShoppingList:)) {
        NSIndexSet *rowIndexes = [shoppingListTableView selectedRowIndexes];
        
        if( [rowIndexes count] > 0 )
            return YES; // enable if there's a selection
        else
            return NO; // otherwise disable
    }
    
    return [super validateMenuItem:menuItem];
}

</code>

I’m just wondering if you can tell me about the relative merits of the two methods (not just the actual method name, but the choice to count the row indexes).

Thanks!

Generic-user-small
02 Feb 2011, 13:48
Ric Levy (21 posts)

Well, I’ve learned two things after more study of your version: 1) the validation should default to NO 2) you nest the if statements so the method does not return anything unless it is being queried by the appropriate menu action.

So I have amended my version:

- (BOOL)validateUserInterfaceItem:(id < NSValidatedUserInterfaceItem >)anItem
{
	if ([anItem action] == @selector(removeItemFromShoppingList:))
		{
			if ([shoppingListTableView selectedRow] > -1)
		return YES;
	else
		return NO;
		}
		
	return [super validateUserInterfaceItem:anItem];
}

So my three questions are: 1) What is the advantage of validateMenuItem: over validateUserInterfaceItem:? 2) What is the advantage of counting row indexes over just establishing that nothing is selected? 3) Why do we return super inside an if statement?

Thanks!

Generic-user-small
09 Feb 2011, 09:20
Tim Isted (105 posts)

Hi Ric,

Sorry for the delay - I’ve been in the internet-disconnected middle of nowhere for a while.

1) For user interface validation, there is also a @validateToolbarItem:@ method. If you have a menu item that performs the same selector as a toolbar item, using @validateUserInterfaceItem:@ eliminates having to write the same code twice. I chose @validateMenuItem:@ for the example code, as it’s the most obviously named method for the task in hand, therefore the easiest to find for someone new to the subject. The Apple docs do suggest you use @validateUserInterfaceItem:@ though, for the reason above (see Enabling Menu Items, specifically the section “Choosing validateMenuItem: or validateUserInterfaceItem:”).

2) I can’t see any reason why “at least one row is selected” and “it’s not the case that nothing is selected” aren’t equivalent statements as far as @NSTableView@ is concerned, so your solution is fine, and good in that it uses fewer lines of code. I guess I’m just keen to establish (and spell out in code) what needs to be true, as without a comment, it’s not immediately obvious that “> -1” means nothing is selected… but that’s a question of personal preference!

3) the @return [super@ happens at the end of the method. If nothing earlier has returned (i.e., the @[anItem action]@ wasn’t the relevant selector), then the overridden implementation will be left to handle everything else. In general, it’s really better to exit early in methods, so you could rewrite the method like this:

- (BOOL)validateUserInterfaceItem:(id < NSValidatedUserInterfaceItem >)anItem
{
    if ([anItem action] != @selector(removeItemFromShoppingList:))
        return [super validateUserInterfaceItem:anItem];

    // we only get to this point if the action is the one we want to validate
    if( [shoppingListTableView selectedRow] > -1 )
        return YES;
    else
        return NO;
}

i.e. if the action isn’t the one to validate, we defer immediately to super, otherwise we perform the check.

But, I’d argue that in the case of a method like this, it’s better to use the earlier style—otherwise, consider what happens if you’re using the method to validate more than one item.

You must be logged in to comment