Melhor maneira de implementar Enums com dados principais

Qual é a melhor maneira de associar entidades de Core Data a valores de enumeração para que eu seja capaz de atribuir uma propriedade de tipo à entidade? Em outras palavras, eu tenho uma entidade chamada Item com uma propriedade itemType que eu quero estar vinculado a um enum, qual é a melhor maneira de fazer isso.

Você terá que criar assessores personalizados se quiser restringir os valores a um enum. Então, primeiro você declararia um enum, assim:

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

Em seguida, declare getters e setters para sua propriedade. Não é uma boa idéia replace os existentes, já que os acessadores padrão esperam um object NSNumber em vez de um tipo escalar, e você terá problemas se alguma coisa nos bindings ou sistemas KVO tentar e acessar seu valor.

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

Finalmente, você deve implementar + keyPathsForValuesAffecting para obter notifications de KVO para itemTypeRaw quando itemType é alterado.

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

Você pode fazer isso de maneira mais simples:

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

E no seu modelo, defina itemType como um número de 16 bits. Tudo feito. Nenhum código adicional é necessário. Basta colocar o seu habitual

 @dynamic itemType; 

Se você estiver usando o Xcode para criar sua subclass NSManagedObject , verifique se a configuração ” usar propriedades escalares para tipos de dados primitivos ” está marcada.

Uma abordagem alternativa que estou considerando não é declarar um enum, mas sim declarar os valores como methods de categoria no NSNumber.

Se você estiver usando o mogenerator, dê uma olhada nisso: https://github.com/rentzsch/mogenerator/wiki/Using-enums-as-types . Você pode ter um atributo Integer 16 chamado itemType , com um valor attributeValueScalarType de Item nas informações do usuário. Em seguida, nas informações do usuário para sua entidade, defina additionalHeaderFileName como o nome do header no qual o Item enum está definido. Ao gerar seus arquivos de header, o mogenerator fará automaticamente com que a propriedade tenha o tipo Item .

Eu defino o tipo de atributo como um inteiro de 16 bits e uso isto:

 #import  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 

Como as enumerações são suportadas por um padrão curto, você também não pode usar o wrapper NSNumber e definir a propriedade diretamente como um valor escalar. Certifique-se de definir o tipo de dados no modelo de core data como “Integer 32”.

MyEntity.h

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

Em outro lugar no código

 myEntityInstance.coreDataEnumStorage = kEnumThing; 

Ou análise de uma sequência JSON ou carregamento de um arquivo

 myEntityInstance.coreDataEnumStorage = [myStringOfAnInteger intValue]; 

O código colado abaixo funciona para mim e eu o adicionei como um exemplo completo de trabalho. Gostaria de ouvir opiniões sobre essa abordagem, já que planejo usá-la amplamente em todos os meus aplicativos.

  • Eu deixei o @dynamic no lugar, pois é então satisfeito pelo getter / setter nomeado na propriedade.

  • De acordo com a resposta do iKenndac, eu não substituí os nomes padrão de getter / setter.

  • Eu incluí uma verificação de intervalo por meio de um NSAssert nos valores válidos typedef.

  • Eu também adicionei um método para obter um valor de string para o typedef dado.

  • Prefixo constantes com “c” em vez de “k”. Eu sei o raciocínio por trás de “k” (origens de matemática, histórico), mas parece que estou lendo código ESL com ele, então eu uso “c”. Apenas uma coisa pessoal.

Há uma pergunta semelhante aqui: typedef como um tipo de dados Core

Eu apreciaria qualquer input nesta abordagem.

 Word.h #import  #import  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 

Eu fiz muito isso e encontrei o seguinte formulário para ser útil:

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

Nesse caso, o enum é bem simples:

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

e chamo pedantic, mas eu uso enums para nomes de campos, como este:

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

Como isso pode ser trabalhoso para modelos de dados complexos, eu escrevi um gerador de código que consome o MOM / entidades para cuspir todos os mapeamentos. Minhas inputs acabam sendo um dictionary do tipo Tabela / Linha para Enum. Enquanto eu estava nisso, também gerei código de serialização JSON. Eu fiz isso para modelos muito complexos e acabou por ser uma grande economia de tempo.