8

I'm working on a project which would be ideally suit Cocoa bindings for the UI but I'm having an issue binding the value of an object property and can't find a suitable solution. The object is as follows:

typedef enum tagCSQuality {
    kQualityBest            = 0,
    kQualityWorst           = 1
} CSQuality;

@interface CSProfile : NSObject {
   NSString *identifier;
   NSString *name;
   CSQuality quality;
}

In the XIB, I have an object controller whose content object is bound to a "currentSelection" property of the window controller which is an instance of the above object. I've then bound the name and identifier which all work as expected but I cannot see how I can bind the enums.

Ideally I would like an NSPopupButton to display "Best" and "Worst" and pick the correct enum value. I have updated the enum to have an explicit numeric value and I believe that I need a value transformer to convert the values but I'm stuck on exactly how this could be implemented.

Can anyone help me out or point me in the right direction?

Thanks, J

JWood
  • 2,804
  • 2
  • 39
  • 64
  • There HAS to be an easier way to do all this. I've been searching for a wrapper class that will just wrap, unwrap, count, and bind `typedef` `enums` etc without a total brain-drain. SO far no luck. – Alex Gray Sep 03 '12 at 19:45

3 Answers3

8

You can use an NSValueTransformerfor this.

Since the enumeration values are integers only, they are encapsulated in an NSNumber object.

An valid transformer could look like the following.

+(Class)transformedValueClass {
    return [NSString class];
}

-(id)transformedValue:(id)value {
    CSQuality quality = [value intValue];
    if (quality == kQualityBest)
        return @"Best";
    else if (quality == kQualityWorst)
        return @"Worst";

    return nil;
}

This can be bound to the Selected Value binding of the NSPopupButton.

If you want to create a bidirectional binding (i.e. be able to select something in the NSPopupButton you have to add the following code for the reverse transformation:

+(BOOL)allowsReverseTransformation {
    return YES;
}

-(id)reverseTransformedValue:(id)value {
    if ([@"Worst" isEqualToString:value]) 
        return [NSNumber numberWithInt: kQualityWorst];
    else if ([@"Best" isEqualToString:value]) 
        return [NSNumber numberWithInt: kQualityBest];

    return nil;
}
Sebastian
  • 96
  • 6
4

An enum is not an object. Cocoa bindings are a way to connect model objects to view objects.

NSResponder
  • 16,861
  • 7
  • 32
  • 46
  • Thanks, I realise that. My question is how would I update the enum value via bindings? I'm sure it must be possible via a transformer and an NSNumber object somehow. I guess the obvious way is to have a separate property of NSNumber* and update in the get/set selectors but I'm just wondering if there is a "correct" way to do it. – JWood Aug 22 '11 at 15:57
2

If you are using Interface Builder, you can embed enum represented integer for each NSMenuItem items through property panel. Then select NSPopUpButton and specify binding 'selected tag' to the property with key path.

In this example, assume, IB's file owner is CSProfile. Prepare NSPopUpButton with two NSMenuItem items and tag them with 0(kQualityBest) and 1(kQualityWorst). Then navigate 'selected tag' of NSPopUpButton and check bind to 'File's owner'(CSProfile) with Model Key Path 'quality'.

@interface CSProfile : NSObject {
   NSString *identifier;
   NSString *name;
   CSQuality quality;
}
@property (assign) CSQuality quality;
Kaz Yoshikawa
  • 1,577
  • 1
  • 18
  • 26