3
votes

Assuming I have an NSObject subclass representing a country, e.g.

@interface CountryInfo : NSObject

@property (nonatomic, retain) NSString *countryName;

My model contains an NSMutableArray of CountryInfos. I want to bind the array to an NSComboBox. The combo box should display the country name, and allow the user to select a country.

So, I set up my .xib like so:

CountryArrayController (NSArrayController)

ContentArray

  • Bind to: File's Owner > Model Key Path: self.model.countries

NSComboBox

Content

  • Bind to: CountryArrayController > Controller Key: arrangedObjects

Content Values

  • Bind to: CountryArrayController > Controller Key: arrangedObjects > Model Key Path: countryName

So far, so good. Now, how to bind the Value of the NSComboBox? The documentation states:

"An NSString or NSNumber that specifies the value of the NSComboBox."

What does this mean? I note that I can bind this to an NSString on my model, and it will reflect the selected countryName. But I want to bind to the CountyInfo object itself! Whether directly, or through binding to the selection on my array controller: how can I set this up?

2
Have you tried using an NSValueTransformer?macandyp
Hi @macandyp, yes a NSValueTransformer would indeed work and I can get the same behaviour by binding on the string value and manually converting in code. It just seems bizarre that I have to write extra code to achieve this, and can't just bind to the object (which is what I am used to). Thanks!TheNextman
I agree it's a bit weird. I know that if you bind to content, and not bind content values, it will invoke the description of your class to populate the strings for the combo box. I don't know if that helps you, though.macandyp

2 Answers

10
votes

I was approaching this wrong - the correct control to use was NSPopUpButton rather than NSComboBox.

NSComboBox has a different behaviour because it needs to support the scenario where the user directly enters text. NSPopUpButton is designed to only work with a predefined set of values and behaves as expected vis-a-vis it's "selection" bindings.

1
votes

This issue doesn't seem to have a simple solution, here is the one I found, implementing a NSArrayController category :

@interface NSArrayController( ComboBoxCompatibility )
@property(readwrite )NSString *firstSelectedObject;
@end

And for the getters and setters :

@implementation NSArrayController (ComboBoxCompatibility)
-(NSString *)firstSelectedObject
{
    return [[self selectedObjects] firstObject];
}
-(void)setFirstSelectedObject:(NSString *)firstSelectedObject
{
    NSUInteger idx = [[self arrangedObjects] indexOfObject:firstSelectedObject];
    [self setSelectionIndex:idx];
}
@end

You can then bind the value of the NSComboBox to your array controller's firstSelectedObject as soon as the objects in it implement copyWithZone: you can also modify the above code if the objects aren't strings but have a single property, "name" for example that you display in the combo box list by replacing [self arrangedObjects] with [[self arrangedObjects] valueForKey:@"name"] in the setter and [[[self arrangedObject] firstObject] valueForKey:@"name"] in the getter