3

I'd like to display some data of my model within a status bar menu. So, I bound my entity-object to the title of an NSMenuItem:

        [self.statusMenu setAutoenablesItems:NO];

        NSMenuItem * exportMenuItem = [[NSMenuItem alloc] init];
        [exportMenuItem bind:@"title" toObject:expo withKeyPath:@"menuItemTitle" options:nil];
        [exportMenuItem setEnabled:NO];

        [self.statusMenu insertItem:exportMenuItem atIndex:3];

It works fine so far from init. But when I update my Model it does not updates the title of the NSMenuItem.

Jason
  • 2,503
  • 3
  • 38
  • 46
martn_st
  • 2,576
  • 1
  • 24
  • 30
  • It's impossible to say why your menu item title isn't updating without knowing more about the object `expo`. Is it KVO-compliant for the key `menuItemTitle`? How is the value for `menuItemTitle` being updated? (You might also want to use `NSTitleBinding` instead of `@"title"`.) – ipmcc Dec 06 '12 at 17:53
  • @ipmcc Hey, due to your answer I guess the reason. `menuItemTitle`isn't a real property. It's just a method that combines different properties of expo to a single string. (accepted `NSTitleBinding`) – martn_st Dec 06 '12 at 20:38

2 Answers2

0

Okay I got it:

menuItemTitle is a dynamic getter method which combines two actual properties of expo. So the reason for NSMenuItem's title to not get updated is probably, that menuItemTitle probably never gets actually set.

So how do I tell, that menuItemTitle was changed, when one of my properties was set? Overriding expo's setters to add [self willChangeValueForKey:@"menuItemTitle"]; and [self didChangeValueForKey:@"menuItemTitle"]; does not work as it causes an endless loop in calling the setter itself again and again.

So here is my solution: I overrode [NSManagedObject setValue:(id)value forKey:(NSString *)key]:

- (void)setValue:(id)value forKey:(NSString *)key {
    [self willChangeValueForKey:@"menuItemTitle"];
    [super setValue:value forKey:key];
    [self didChangeValueForKey:@"menuItemTitle"];
}
martn_st
  • 2,576
  • 1
  • 24
  • 30
0

For reference, the canonical solution to this issue is to implement a class method like this:

+ (NSSet *)keyPathsForValuesAffectingMenuItemTitle
{
    return [NSSet setWithObjects: @"propertyMenuItemTitleDependsOn1", 
                                  @"propertyMenuItemTitleDependsOn2",
                                  nil];
}

If you implement a method like this, then the framework will handle calling willChangeValueForKey: and didChangeValueForKey: for the key menuItemTitle any time any of the other properties are changed.

ipmcc
  • 29,581
  • 5
  • 84
  • 147