核心数据实现枚举的最佳方式
将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属性,在用户信息中具有Item
的attributeValueScalarType
值。 然后,在实体的用户信息中,将additionalHeaderFileName
设置为Item
枚举定义的头部名称。当生成头文件时,mogenerator将自动使该属性具有Item
types。
我将属性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序列化代码。 我已经为非常复杂的模型做了这个,结果是节省了很多时间。
- Swift 2,警告:无法从dyld共享caching中加载任何Objective-C类信息
- 我可以在iPhone的Core Data中使用Transformable属性types来做些什么?
- 核心数据VS Sqlite或FMDB …?
- Xcode 6 iOS 8 iCloud核心数据设置
- 最佳实践? – 数组/字典作为核心数据实体属性
- 我怎样才能投到NSManagedObject但不是我的实体的types?
- 如何将iPhone Core Data与Web服务器同步,然后推送到其他设备?
- 如何asynchronous同步CoreData和REST Web服务,同时正确地将任何REST错误传播到UI中
- 如何在核心数据中存储图像