将核心数据实体绑定到枚举值的最佳方法是什么,以便我能够为实体分配类型属性?换句话说,我有一个名为Item
的实体,其itemType
属性我希望绑定到枚举,实现此目的的最佳方法是什么。
答案 0 :(得分:129)
如果要将值限制为枚举,则必须创建自定义访问器。所以,首先你要声明一个枚举,如下所示:
typedef enum {
kPaymentFrequencyOneOff = 0,
kPaymentFrequencyYearly = 1,
kPaymentFrequencyMonthly = 2,
kPaymentFrequencyWeekly = 3
} PaymentFrequency;
然后,为您的财产声明getter和setter。覆盖现有的是一个坏主意,因为标准访问器期望NSNumber对象而不是标量类型,如果绑定或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"];
}
答案 1 :(得分:78)
你可以这样做,更简单:
typedef enum Types_e : int16_t {
TypeA = 0,
TypeB = 1,
} Types_t;
@property (nonatomic) Types_t itemType;
在您的模型中,将itemType
设置为16位数字。全部完成。无需其他代码。只需按照惯例加入
@dynamic itemType;
如果您正在使用Xcode创建NSManagedObject
子类,请确保选中“使用原始数据类型的标量属性”设置。
答案 2 :(得分:22)
我正在考虑的另一种方法是不要声明枚举,而是将值声明为NSNumber上的类别方法。
答案 3 :(得分:5)
如果你正在使用mogenerator,请看一下:https://github.com/rentzsch/mogenerator/wiki/Using-enums-as-types。您可以在用户信息中使用名为itemType
的Integer 16属性,其attributeValueScalarType
值为Item
。然后,在实体的用户信息中,将additionalHeaderFileName
设置为定义Item
枚举的标题的名称。生成头文件时,mogenerator将自动使属性具有{{ 1}}类型。
答案 4 :(得分:2)
我将属性类型设置为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
答案 5 :(得分:1)
由于枚举由标准短片支持,因此您也不能使用NSNumber包装器并将属性直接设置为标量值。确保将核心数据模型中的数据类型设置为“整数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;
或者从JSON字符串解析或从文件加载
myEntityInstance.coreDataEnumStorage = [myStringOfAnInteger intValue];
答案 6 :(得分:0)
下面粘贴的代码对我有用,我已将其添加为完整的工作示例。我想听听有关这种方法的意见,因为我打算在我的应用程序中广泛使用它。
我已经离开了@dynamic,因为它在属性中命名的getter / setter就满足了。
根据iKenndac的回答,我没有覆盖默认的getter / setter名称。
我在typedef有效值上通过NSAssert包含了一些范围检查。
我还添加了一个方法来获取给定typedef的字符串值。
我将常量加上“c”而不是“k”。我知道“k”(数学起源,历史)背后的原因,但感觉就像我正在阅读ESL代码,所以我使用“c”。只是个人的事情。
这里有一个类似的问题:typedef as a Core data type
我很欣赏这种方法的任何意见。
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
答案 7 :(得分:0)
我已经做了很多,发现以下表格很有用:
// 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 /实体来吐出所有映射。我的输入最终是从表/行到枚举类型的字典。在我的时候,我也生成了JSON序列化代码。我已经为非常复杂的模型做了这件事,结果证明它可以节省大量时间。
答案 8 :(得分:0)
如果创建一个名为“ YourClass”的实体,Xcode将自动在“数据模型检查器”中选择“类定义”作为默认的Codegen类型。这将在下面生成类:
// YourClass+CoreDataClass.swift
@objc(YourClass)
public class YourClass: NSManagedObject {
}
// YourClass+CoreDataClass.h
@interface YourClass : NSManagedObject
@end
#import "YourClass+CoreDataProperties.h"
// YourClass+CoreDataClass.m
#import "YourClass+CoreDataClass.h"
@implementation YourClass
@end
我们将从Codegen选项中选择“类别/扩展名”,而不是Xcode中的“类定义”。
现在,如果要添加枚举,请为您自动生成的类创建另一个扩展,然后在此处添加您的枚举定义,如下所示:
// YourClass+Extension.h
#import "YourClass+CoreDataClass.h" // That was the trick for me!
@interface YourClass (Extension)
@end
// YourClass+Extension.m
#import "YourClass+Extension.h"
@implementation YourClass (Extension)
typedef NS_ENUM(int16_t, YourEnumType) {
YourEnumTypeStarted,
YourEnumTypeDone,
YourEnumTypePaused,
YourEnumTypeInternetConnectionError,
YourEnumTypeFailed
};
@end
现在,如果要将值限制为枚举,则可以创建自定义访问器。 Please check the accepted answer by question owner。或者,您可以在使用枚举运算符通过显式转换方法设置枚举时转换枚举,如下所示:
model.yourEnumProperty = (int16_t)YourEnumTypeStarted;
Xcode现在支持自动生成NSManagedObject子类 在建模工具中。在实体检查器中:
“手动/无”是默认设置,并且是以前的行为;在这种情况下,你 应该实现自己的子类或使用NSManagedObject。 类别/扩展名在名为like的文件中生成类扩展名 ClassName + CoreDataGeneratedProperties。您需要声明/实现 主类(如果在Obj-C中,则可以通过扩展名导入标头 命名为ClassName.h)。类定义生成名为的子类文件 如ClassName + CoreDataClass以及为生成的文件 类别/扩展名。生成的文件放置在DerivedData和 保存模型后,将在第一个构建中重新构建。他们也是 由Xcode索引,因此在引用上单击命令并快速打开 按文件名起作用。