La mejor manera de implementar Enumeraciones con datos básicos


¿Cuál es la mejor manera de vincular entidades de Datos Principales a valores de enumeración para que pueda asignar una propiedad de tipo a la entidad? En otras palabras, tengo una entidad llamada Item con una propiedad itemType que quiero estar vinculada a una enumeración, cuál es la mejor manera de hacerlo.

Author: Peter Hosey, 2009-10-26

8 answers

Tendrá que crear accesos personalizados si desea restringir los valores a una enumeración. Entonces, primero declararías una enumeración, así:

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

Luego, declare getters y setters para su propiedad. Es una mala idea anular los existentes, ya que los accesores estándar esperan un objeto NSNumber en lugar de un tipo escalar, y se encontrará con problemas si algo en los enlaces o sistemas KVO intenta acceder a su valor.

- (PaymentFrequency)itemTypeRaw {
    return (PaymentFrequency)[[self itemType] intValue];
}

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

Finalmente, debe implementar + keyPathsForValuesAffecting<Key> para obtener Notificaciones KVO para itemTypeRaw cuando ItemType cambia.

+ (NSSet *)keyPathsForValuesAffectingItemTypeRaw {
    return [NSSet setWithObject:@"itemType"];
}
 129
Author: iKenndac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-01 13:51:35

Puedes hacerlo de esta manera, mucho más simple:

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

@property (nonatomic) Types_t itemType;

Y en su modelo, establezca itemType como un número de 16 bits. Todo listo. No se necesita código adicional. Solo tiene que poner en su habitual

@dynamic itemType;

Si estás usando Xcode para crear tu subclase NSManagedObject, asegúrate de que la opción "usar propiedades escalares para tipos de datos primitivos" esté marcada.

 78
Author: Daniel Eggert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-28 20:38:11

Un enfoque alternativo que estoy considerando es no declarar una enumeración en absoluto, sino declarar los valores como métodos de categoría en NSNumber.

 22
Author: Mike Abdullah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-16 16:58:48

Si estás usando mogenerator, echa un vistazo a esto: https://github.com/rentzsch/mogenerator/wiki/Using-enums-as-types . Puede tener un atributo Entero 16 llamado itemType, con un valor attributeValueScalarType de Item en la información del usuario. Luego, en la información de usuario de su entidad, establezca additionalHeaderFileName al nombre del encabezado en el que está definida la enumeración Item. Al generar sus archivos de cabecera, mogenerator automáticamente hará que la propiedad tenga el tipo Item.

 5
Author: jfla,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-30 17:17:08

Establezco el tipo de atributo como entero de 16 bits y luego uso esto:

#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
 2
Author: malhal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-28 07:37:24

Dado que las enumeraciones están respaldadas por un short estándar, tampoco podría usar el wrapper NSNumber y establecer la propiedad directamente como un valor escalar. Asegúrese de establecer el tipo de datos en el modelo de datos core como "Integer 32".

MyEntity.h

typedef enum {
kEnumThing, /* 0 is implied */
kEnumWidget, /* 1 is implied */
} MyThingAMaBobs;

@interface myEntity : NSManagedObject

@property (nonatomic) int32_t coreDataEnumStorage;

En otra parte del código

myEntityInstance.coreDataEnumStorage = kEnumThing;

O analizar desde una cadena JSON o cargar desde un archivo

myEntityInstance.coreDataEnumStorage = [myStringOfAnInteger intValue];
 1
Author: puppybits,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-24 16:37:41

El código pegado a continuación funciona para mí, y lo he agregado como ejemplo de trabajo completo. Me gustaría escuchar opiniones sobre este enfoque, ya que planeo usarlo ampliamente en mis aplicaciones.

  • He dejado la @ dinámica en su lugar, ya que es satisfecha por el getter/setter nombrado en la propiedad.

  • Según la respuesta de iKenndac, no he anulado los nombres predeterminados de getter / setter.

  • He incluido algunas comprobaciones de rango a través de un NSAssert en el typedef valores válidos.

  • También he añadido un método para obtener un valor de cadena para el typedef dado.

  • I prefijo constantes con " c "en lugar de"k". Conozco el razonamiento detrás de " k "(orígenes matemáticos, históricos), pero se siente como si estuviera leyendo código ESL con él, así que uso"c". Es algo personal.

Hay una pregunta similar aquí: typedef como un tipo de datos básicos

Agradecería cualquier aportación sobre este enfoque.

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
 0
Author: ardochhigh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:31

He hecho esto mucho y encuentro útil la siguiente forma:

// 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?

En este caso, la enumeración es bastante simple:

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

Y lo llaman pedante, pero yo uso enumeraciones para los nombres de campo, así:

public enum Field:String {

    case Account = "account"
}

Dado que esto puede ser laborioso para modelos de datos complejos, escribí un generador de código que consume la MOM / entidades para escupir todas las asignaciones. Mis entradas terminan siendo un diccionario de tipo Tabla / Fila a enumeración. Mientras estaba en ello, también generé serialización JSON codificar. He hecho esto para modelos muy complejos y ha resultado ser un gran ahorro de tiempo.

 0
Author: Chris Conover,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-24 02:55:38