核心数据实现枚举的最佳方式

将Core Data实体绑定到枚举值的最佳方法是什么,以便我能够为实体指定一个types属性? 换句话说,我有一个名为Item的实体,我想绑定到一个枚举的itemType属性,什么是最好的方式去做这个。

如果要将值限制为枚举,则必须创build自定义访问器。 所以,首先你要声明一个枚举,如下所示:

 typedef enum { kPaymentFrequencyOneOff = 0, kPaymentFrequencyYearly = 1, kPaymentFrequencyMonthly = 2, kPaymentFrequencyWeekly = 3 } PaymentFrequency; 

然后,为你的财产声明getter和setter。 因为标准访问者需要一个NSNumber对象而不是一个标量types,所以覆盖现有的对象是一个坏主意,如果绑定或KVO系统中的任何东西尝试访问你的值,你将遇到麻烦。

 - (PaymentFrequency)itemTypeRaw { return (PaymentFrequency)[[self itemType] intValue]; } - (void)setItemTypeRaw:(PaymentFrequency)type { [self setItemType:[NSNumber numberWithInt:type]]; } 

最后,您应该实现+ keyPathsForValuesAffecting<Key>以便在itemType更改时获取itemTypeRaw的KVO通知。

 + (NSSet *)keyPathsForValuesAffectingItemTypeRaw { return [NSSet setWithObject:@"itemType"]; } 

你可以这样做,更简单:

 typedef enum Types_e : int16_t { TypeA = 0, TypeB = 1, } Types_t; @property (nonatomic) Types_t itemType; 

在您的模型中,将itemType设置为16位数字。 全做完了。 没有额外的代码需要。 只要把你平常

 @dynamic itemType; 

如果您使用Xcode创build您的NSManagedObject子类,请确保选中“ 使用基元数据types的标量属性 ”设置。

我正在考虑的另一种方法是不要声明枚举,而是将值声明为NSNumber上的类别方法。

如果你使用mogenerator,看看这个: https : //github.com/rentzsch/mogenerator/wiki/Using-enums-as-types 。 您可以拥有一个名为itemType的Integer 16属性,在用户信息中具有ItemattributeValueScalarType值。 然后,在实体的用户信息中,将additionalHeaderFileName设置为Item枚举定义的头部名称。当生成头文件时,mogenerator将自动使该属性具有Itemtypes。

我将属性types设置为16位整数,然后使用这个:

 #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 

由于枚举是由一个标准短的支持,你也可以不使用NSNumber包装,直接设置属性作为标量值。 确保将核心数据模型中的数据types设置为“整数32”。

MyEntity.h

 typedef enum { kEnumThing, /* 0 is implied */ kEnumWidget, /* 1 is implied */ } MyThingAMaBobs; @interface myEntity : NSManagedObject @property (nonatomic) int32_t coreDataEnumStorage; 

在代码的其他地方

 myEntityInstance.coreDataEnumStorage = kEnumThing; 

或从JSONstringparsing或从文件加载

 myEntityInstance.coreDataEnumStorage = [myStringOfAnInteger intValue]; 

下面粘贴的代码适用于我,我已经把它作为完整的工作示例。 我想听听这种方法的意见,因为我打算在我的应用程序中广泛使用它。

  • 我已经离开了@dynamic,因为它是由在属性中命名的getter / setter满足。

  • 根据iKenndac的回答,我没有重写默认的getter / setter名称。

  • 我已经通过NSAssert在typedef有效值包括一些范围检查。

  • 我也添加了一个方法来获得给定typedef的string值。

  • 我用“c”而不是“k”作为常量前缀。 我知道“k”(math起源,历史)背后的原因,但感觉就像我正在阅读ESL代码一样,所以我使用“c”。 只是个人的事情。

这里有一个类似的问题: typedef作为核心数据types

我会很感激这个方法的任何意见。

 Word.h #import <Foundation/Foundation.h> #import <CoreData/CoreData.h> typedef enum { cPresent = 0, cFuturProche = 1, cPasseCompose = 2, cImparfait = 3, cFuturSimple = 4, cImperatif = 5 } TenseTypeEnum; @class Word; @interface Word : NSManagedObject @property (nonatomic, retain) NSString * word; @property (nonatomic, getter = tenseRaw, setter = setTenseRaw:) TenseTypeEnum tense; // custom getter & setter methods -(void)setTenseRaw:(TenseTypeEnum)newValue; -(TenseTypeEnum)tenseRaw; - (NSString *)textForTenseType:(TenseTypeEnum)tenseType; @end Word.m #import "Word.h" @implementation Word @dynamic word; @dynamic tense; // custom getter & setter methods -(void)setTenseRaw:(TenseTypeEnum)newValue { NSNumber *numberValue = [NSNumber numberWithInt:newValue]; [self willChangeValueForKey:@"tense"]; [self setPrimitiveValue:numberValue forKey:@"tense"]; [self didChangeValueForKey:@"tense"]; } -(TenseTypeEnum)tenseRaw { [self willAccessValueForKey:@"tense"]; NSNumber *numberValue = [self primitiveValueForKey:@"tense"]; [self didAccessValueForKey:@"tense"]; int intValue = [numberValue intValue]; NSAssert(intValue >= 0 && intValue <= 5, @"unsupported tense type"); return (TenseTypeEnum) intValue; } - (NSString *)textForTenseType:(TenseTypeEnum)tenseType { NSString *tenseText = [[NSString alloc] init]; switch(tenseType){ case cPresent: tenseText = @"présent"; break; case cFuturProche: tenseText = @"futur proche"; break; case cPasseCompose: tenseText = @"passé composé"; break; case cImparfait: tenseText = @"imparfait"; break; case cFuturSimple: tenseText = @"futur simple"; break; case cImperatif: tenseText = @"impératif"; break; } return tenseText; } @end 

我已经做了很多,find下面的表单是有用的:

 // accountType public var account:AccountType { get { willAccessValueForKey(Field.Account.rawValue) defer { didAccessValueForKey(Field.Account.rawValue) } return primitiveAccountType.flatMap { AccountType(rawValue: $0) } ?? .New } set { willChangeValueForKey(Field.Account.rawValue) defer { didChangeValueForKey(Field.Account.rawValue) } primitiveAccountType = newValue.rawValue }} @NSManaged private var primitiveAccountType: String? 

在这种情况下,枚举非常简单:

 public enum AccountType: String { case New = "new" case Registered = "full" } 

并称它迂腐,但我使用枚举字段名称,如下所示:

 public enum Field:String { case Account = "account" } 

由于这可能会使复杂的数据模型变得费力,我写了一个代码生成器,它使用MOM /实体来吐出所有的映射。 我的input最终是从表/行到枚举types的字典。 当我在这里,我也生成了JSON序列化代码。 我已经为非常复杂的模型做了这个,结果是节省了很多时间。