Best way to implement Enums with Core Data
Solution 1
You'll have to create custom accessors if you want to restrict the values to an enum. So, first you'd declare an enum, like so:
typedef enum {
kPaymentFrequencyOneOff = 0,
kPaymentFrequencyYearly = 1,
kPaymentFrequencyMonthly = 2,
kPaymentFrequencyWeekly = 3
} PaymentFrequency;
Then, declare getters and setters for your property. It's a bad idea to override the existing ones, since the standard accessors expect an NSNumber object rather than a scalar type, and you'll run into trouble if anything in the bindings or KVO systems try and access your value.
- (PaymentFrequency)itemTypeRaw {
return (PaymentFrequency)[[self itemType] intValue];
}
- (void)setItemTypeRaw:(PaymentFrequency)type {
[self setItemType:[NSNumber numberWithInt:type]];
}
Finally, you should implement + keyPathsForValuesAffecting<Key>
so you get KVO notifications for itemTypeRaw when itemType changes.
+ (NSSet *)keyPathsForValuesAffectingItemTypeRaw {
return [NSSet setWithObject:@"itemType"];
}
Solution 2
You can do this way, way simpler:
typedef enum Types_e : int16_t {
TypeA = 0,
TypeB = 1,
} Types_t;
@property (nonatomic) Types_t itemType;
And in your model, set itemType
to be a 16 bit number. All done. No additional code needed. Just put in your usual
@dynamic itemType;
If you're using Xcode to create your NSManagedObject
subclass, make sure that the "use scalar properties for primitive data types" setting is checked.
Solution 3
An alternative approach I'm considering is not to declare an enum at all, but to instead declare the values as category methods on NSNumber.
Solution 4
If you're using mogenerator, have a look at this: https://github.com/rentzsch/mogenerator/wiki/Using-enums-as-types. You can have an Integer 16 attribute called itemType
, with a attributeValueScalarType
value of Item
in the user info. Then, in the user info for your entity, set additionalHeaderFileName
to the name of the header that the Item
enum is defined in. When generating your header files, mogenerator will automatically make the property have the Item
type.
Solution 5
I set the attribute type as 16 bit integer then use this:
#import <CoreData/CoreData.h>
enum {
LDDirtyTypeRecord = 0,
LDDirtyTypeAttachment
};
typedef int16_t LDDirtyType;
enum {
LDDirtyActionInsert = 0,
LDDirtyActionDelete
};
typedef int16_t LDDirtyAction;
@interface LDDirty : NSManagedObject
@property (nonatomic, strong) NSString* identifier;
@property (nonatomic) LDDirtyType type;
@property (nonatomic) LDDirtyAction action;
@end
...
#import "LDDirty.h"
@implementation LDDirty
@dynamic identifier;
@dynamic type;
@dynamic action;
@end
Related videos on Youtube
Michael Gaylord
iOS Engineer at Civic Inc. Co-founder of Storie Inc. Founding engineer at Gyft Inc.
Updated on July 08, 2022Comments
-
Michael Gaylord almost 2 years
What is the best way to bind Core Data entities to enum values so that I am able to assign a type property to the entity? In other words, I have an entity called
Item
with anitemType
property that I want to be bound to an enum, what is the best way of going about this. -
Michael Gaylord over 14 yearsInteresting. It definitely seems doable.
-
TheLearner over 12 yearsbrilliant idea! so much easier than creating tables in the db, unless your db is filled from a web service then its probably best to use a db table!
-
Constantino Tsarouhas almost 12 yearsThank you — too bad Core Data doesn't support this natively. I mean: Xcode generates class files, why not
enum
s? -
port5432 over 11 yearsHere's an example: renovatioboy.wordpress.com/2011/10/06/…
-
Anonymous White over 11 yearsThe last code is if you want to observe item itemTypeRaw. However, you can simply observe item itemType instead of itemTypeRaw right?
-
Daniel Eggert over 11 yearsWith Xcode 4.5 you don't need any of this. Take a look at my answer. You just need to define the enum as an
int16_t
and you're set. -
ArtOfWarfare over 11 yearsAre there any limits with which iOS / OS X versions this will work with?
-
Daniel Eggert over 11 yearsIt’s been working for as long as I remember, but I can't make any promises. I remember using this on iOS 5, but I don't know why it wouldn't work with iOS 4...
-
Ivan Vučica about 11 yearsNote, this is a C++11 feature called "enum classes". cprogramming.com/c++11/…
-
Daniel Eggert about 11 yearsNo, this has nothing to do with C++11. It's part of clang 3.3 supporting Enumerations with a fixed underlying type for ObjC. C.f. clang.llvm.org/docs/…
-
Rob about 11 yearsHow do you avoid losing this code every time you regenerate the model class? I have been using Categories so that the core domain entities can be regenerated.
-
Jeff about 11 yearsSince this doesn't have the
retain
keyword, will it still get stored in the database? -
Daniel Eggert about 11 yearsThe
retain
is related to memory management, not whether it gets stored into the database or not. -
Kyle Redfearn about 11 yearsI agree with Rob. I don't want this to have to be regenerated over and over again. I prefer the category.
-
malhal almost 11 yearsSure looks like C++ with all the underscores
-
DonnaLea over 10 years@Rob To avoid the enum being overwritten every time the model class is regenerated, I wrote my typedef in a separate .h header file. So only two things need changing when the file is regenerated, the property type to the enum and re-including the header file with the enum. Not perfect, but the best I could come up with if following this pattern.
-
DonnaLea over 10 yearsI like it. I'm going to use this approach in my project. I like that I can also contain all my other meta information about the meta data within the NSNumber category. (i.e. linking strings to the enum values)
-
Gregarious about 10 yearsReally great idea! Very useful for associating string identifiers, using directly in JSON, Core Data, etc.
-
tapmonkey about 10 years@Rob Categories is a way to do it, but instead you could also use mogenerator: github.com/rentzsch/mogenerator. Mogenerator will generate 2 classes per entity, where one class will always be overwritten on data model changes and the other subclasses that class for custom stuff and never gets overwritten.
-
malhal over 9 yearsI'm getting a bad access with this
-
Wizard of Kneup over 9 yearsHow can you do this in Swift? If I am correct then this "trick" is not reproducible in Swift. See as well my question here: stackoverflow.com/questions/27656219/…
-
Daniel Eggert over 9 yearsSwift
enum
is something very, very different from a C / ObjC enum. I'm not sure if there's any good way to fudge it… -
p0lAris about 9 yearsI have been using this in my code but this throws me errors every time: CoreData: error: Property <> is a scalar type on class <> that does not match its Entity's property's scalar type. Dynamically generated accessors do not support implicit type coercion. Cannot generate a setter method for it. I just want to use the accepted answer after trying so much.
-
Gagan Joshi almost 9 years@Daniel Eggert , i try to use this but i am getting an error, Declaration of 'int16_t" must be imported from module . Can you help me on that. Many thanks in advance
-
Daniel Eggert almost 9 yearsIn ObjC
int16_t
is already defined if you import Foundation or CoreData. Are you using Swift? You need to make sure that your scalar type in the entity definition matches theint16_t
-> 16 bit. -
malhal almost 9 yearsI was using this technique until I discovered a major problem that doing it this way prevents changedValues from containing the key.
-
LolaRun almost 9 years@p0lAris I've been having the same error , because i thought i was doing the same implementation, but there's one thing you and I didn't notice at first. "typedef enum Types_e : int16_t {" this line, you probably have something like that instead "typedef enum {"
-
malhal over 8 yearsAny chance you could edit Types_e and Types_t to something clearer? thanks
-
robmathers about 8 yearsIf you're getting BAD_ACCESS errors or similar, be sure that the proper type (i.e.
int16_t
) is set in your model file. If you're using Xcode to create yourNSManagedObject
subclass, make sure that the "use scalar properties for primitive data types" setting is checked. -
trapper over 6 years@malhal is right! this seems to mess up CoreData change notifications