Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/43.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 使用核心数据实现枚举的最佳方法_Iphone_Objective C_Cocoa_Cocoa Touch_Core Data - Fatal编程技术网

Iphone 使用核心数据实现枚举的最佳方法

Iphone 使用核心数据实现枚举的最佳方法,iphone,objective-c,cocoa,cocoa-touch,core-data,Iphone,Objective C,Cocoa,Cocoa Touch,Core Data,将核心数据实体绑定到枚举值的最佳方法是什么,以便我能够为实体指定类型属性?换句话说,我有一个名为Item的实体,它有一个itemType属性,我想将该属性绑定到一个枚举,最好的方法是什么。如果要将值限制到一个枚举,就必须创建自定义访问器。首先声明一个枚举,如下所示: typedef enum { kPaymentFrequencyOneOff = 0, kPaymentFrequencyYearly = 1, kPaymentFrequencyMonthly = 2,

将核心数据实体绑定到枚举值的最佳方法是什么,以便我能够为实体指定类型属性?换句话说,我有一个名为
Item
的实体,它有一个
itemType
属性,我想将该属性绑定到一个枚举,最好的方法是什么。

如果要将值限制到一个枚举,就必须创建自定义访问器。首先声明一个枚举,如下所示:

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]];
}
最后,您应该实现
+keypathsforvaluesafecting
,以便在itemType更改时获得itemTypeRaw的KVO通知

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

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

由于枚举由标准short支持,因此也不能使用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];

下面粘贴的代码适用于我,我将其添加为完整的工作示例。我想听听大家对这种方法的看法,因为我计划在我的应用程序中广泛使用它

  • 我将@dynamic保留在原地,因为属性中命名的getter/setter满足了它

  • 根据iKenndac的回答,我没有覆盖默认的getter/setter名称

  • 我已经在typedef有效值上包含了一些通过NSAssert进行的范围检查

  • 我还添加了一个方法来获取给定typedef的字符串值

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

这里有一个类似的问题:

我非常感谢您对这一方法的任何意见

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
Word.h
#进口
#进口
类型定义枚举{
cPresent=0,
cFuturProche=1,
cPasseCompose=2,
cImparfait=3,
cFuturSimple=4,
cImperatif=5
}铁线蕨;
@类词;
@接口字:NSManagedObject
@属性(非原子,保留)NSString*字;
@属性(非原子,getter=tenseRaw,setter=settenseaw:)tensetypeaneum-tension;
//自定义getter和setter方法
-(void)settenseaw:(tensetypeaneum)newValue;
-(Tensetypeneum)tenseRaw;
-(NSString*)textForTenseType:(tensetypeneum)tenseType;
@结束
Word.m
#导入“Word.h”
@实现字
@动态词;
@动态时态;
//自定义getter和setter方法
-(void)settenseaw:(tensetypeaneum)newValue
{
NSNumber*numberValue=[NSNumber numberwhithint:newValue];
[任性改变价值观:时态];
[self-setPrimitiveValue:numberValue-forKey:@“时态”];
[self-didChangeValueForKey:@“时态”];
}
-(Tensetypeneum)tenseRaw
{
[任性:@“时态”];
NSNumber*numberValue=[self-primitiveValueForKey:@“时态”];
[赛尔夫·福基:@“时态”];
int intValue=[numberValue intValue];

NSAssert(intValue>=0&&intValue您可以通过更简单的方式执行此操作:

typedef enum Types_e : int16_t {
    TypeA = 0,
    TypeB = 1,
} Types_t;

@property (nonatomic) Types_t itemType;
在您的模型中,将
itemType
设置为16位数字。全部完成。无需额外的代码。只需输入您通常的

@dynamic itemType;

如果使用Xcode创建
NSManagedObject
子类,请确保选中“对基本数据类型使用标量属性”设置。

我将属性类型设置为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

如果您使用的是mogenerator,请查看以下内容:。您可以有一个名为
itemType
的整数16属性,用户信息中的
attributeValueScalarType
值为
Item
。然后,在实体的用户信息中,将
additionalHeaderFileName
设置为
项所包含的头的名称um在中定义。生成头文件时,mogenerator将自动使属性具有
类型。

我做了很多,发现以下表单很有用:

// 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序列化代码。我已经为非常复杂的模型完成了这项工作,结果证明这是一个大问题me saver.

自动生成类的解决方案 来自Xcode的代码生成器(ios 10及以上版本) 如果您创建一个名为“YourClass”的实体,Xcode将自动选择“Class Definition”作为“数据模型检查器”的默认Codegen类型。这将生成以下类:

Swift版本: 目标-C版本: 我们将从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
model.yourEnumProperty = (int16_t)YourEnumTypeStarted;
现在,如果要将值限制为一个枚举,您可以创建自定义访问器。或者,您可以在使用cast运算符使用显式转换方法设置枚举时转换枚举,如下所示:

// 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
model.yourEnumProperty = (int16_t)YourEnumTypeStarted;

Xcode自动子类生成 Xcode现在支持自动生成NSManagedObject子类 在建模工具中。在实体检查器中:

Manual/None是默认值,也是以前的行为;在本例中,您可以 应该实施y
model.yourEnumProperty = (int16_t)YourEnumTypeStarted;