开发者

Using enums with Core Data

开发者 https://www.devze.com 2023-04-06 20:12 出处:网络
What is the best way to handle a helper table (I think there\'s a more technical word for that but it\'s escaping me at the moment)?For instance, my object named Entity has an entity_type property.Tha

What is the best way to handle a helper table (I think there's a more technical word for that but it's escaping me at the moment)? For instance, my object named Entity has an entity_type property. That entity_type needs a string description along with it. Let's assume there are only a handful of entity_types possible.

So I can see going a few ways:

  1. Having another Core Data entity object n开发者_高级运维ame Entity_Type and joining it to-many so that I can obtain the description easily. This will allow me to use in a UIPickerView easily, for example.

  2. I could also see why #1 is a trap because later on I will need to do something like a switch/case to handle specific functionality for each type. Being a Core Data object, I have no "id" per say in order to do the switch statement. The alternative would be to hard code an enum, but then how would I handle the descriptions?

  3. Maybe a combination of the two?

Any advice or experience with a similar situation would greatly help. I tried searching, but all I turned up was how to find the ID of a CD object, which is irrelevant.


The 'combination' approach you speak of would work something like this:

You have your Entity_Type with a string description, and an NSNumber 'enumValue' attribute.

Then you define an enum type with explicit values for forwards and backwards compatibility (you don't want people inserting a new enum at the top and breaking everything).

// these values must not change
enum Foo {
    FooType1 = 1,
    FooType2 = 2
};

Now, you don't want to deal with your 'enumValue' attribute as an NSNumber, so rather than using @dynamic to generate the property, you define your own getter/setter to expose a native enum value rather than an NSNumber. Something like this:

- (void)setEnumValue:(enum Foo)newValue
{
    NSNumber *numberValue = [NSNumber numberWithInt:newValue];
    [self willChangeValueForKey:@"enumValue"];
    [self setPrimitiveValue:numberValue forKey:@"enumValue"];
    [self didChangeValueForKey:@"enumValue"];
}

- (enum Foo)enumValue
{
    [self willAccessValueForKey:@"enumValue"];
    NSNumber *numberValue = [self primitiveValueForKey:@"enumValue"];
    [self didAccessValueForKey:@"enumValue"];

    // optionally validate against possible enum values, maybe handle the case
    // when you are reading a database made by a later version which has new
    // unknown-to-us values, etc.
    return (enum Foo) [numberValue intValue]
}

I have written this code from memory but that's the general gist of things. The getter/setters talk to the underlying managed object's NSNumber value, but your object itself exposes the property as your strongly typed enum type.

You can then define some helper methods to fetch out the associated entity for an enum value. This should just be a simple fetch request with a enumValue == %@ predicate.

You also have to be careful with dealing with unknown enum values. An older version of your software may end up reading a database that contains new enum values that it has no knowledge of.


I've used enums in the past. Like I have a entity to represent a cost and it has a costType which I define as an enum and store in core data as an int. There are 4 possible costTypes (fixed, time, product, travel) and depending on the cost type the cost value will be calculated differently.

I think this is what your getting at, else I'd say give me a firmer example.


I'd suggest two more tools to aid.

  1. Be aware of the NSObject "description" method which you can override, to provide string representation of anything. So if you subclass NSNumber to create an NSNumber that only allows your enumerated set of values, you can also add the "description" method that will simply lookup the value as index in some array of descriptions. Something like

  2. Be very aware of NSValueTransformer! you can create a standalone transformer from any type to any type (and back, for two-way transformers). You can attach a transformer directly to the UI in your .xib, so when you set a NUMERICAL value (your enum) to the UI field, the user will see THE TRANSFORMED (string) value. This also works the other way round.

I'm not attaching code because I'm in a hurry, but I'll do sometime soon.

The above methods are alternative solutions, but maybe you can combine them in the manner suggested by Mike Weller --- Add a new strongly-typed enumerated accessor to the attribute in core-data (which will be some kind of int), but instead of using an enum, use a subclass of NSNumber that has "description" overridden, and Enum accessors as well.

Then define a transformer for this class (into string) that will simply return the description when transforming to string, and will do the opposite when given the description.

Attach this transformer to your UI, and voila!

The techniques described here are Mac too, not just iOS.

0

精彩评论

暂无评论...
验证码 换一张
取 消