ios - switch - swift4 enum
enum Valores para NSString(iOS) (15)
Tengo una enumeración que tiene varios valores:
enum {value1, value2, value3} myValue;
En cierto punto de mi aplicación, deseo verificar qué valor de la enumeración está ahora activo. Estoy usando NSLog, pero no tengo claro cómo mostrar el valor actual de la enumeración (value1 / valu2 / valu3 / etc ...) como NSString para NSLog.
¿Nadie?
una macro:
#define stringWithLiteral(literal) @#literal
una enumeración:
typedef NS_ENUM(NSInteger, EnumType) { EnumType0, EnumType1, EnumType2 };
una matriz:
static NSString * const EnumTypeNames[] = { stringWithLiteral(EnumType0), stringWithLiteral(EnumType1), stringWithLiteral(EnumType2) };
utilizando:
EnumType enumType = ...; NSString *enumName = EnumTypeNames[enumType];
==== EDITAR ====
Copie el siguiente código en su proyecto y ejecútelo.
#define stringWithLiteral(literal) @#literal
typedef NS_ENUM(NSInteger, EnumType) {
EnumType0,
EnumType1,
EnumType2
};
static NSString * const EnumTypeNames[] = {
stringWithLiteral(EnumType0),
stringWithLiteral(EnumType1),
stringWithLiteral(EnumType2)
};
- (void)test {
EnumType enumType = EnumType1;
NSString *enumName = EnumTypeNames[enumType];
NSLog(@"enumName: %@", enumName);
}
A continuación se muestra un ejemplo de Enum Struct que es amigable para Objective-C en caso de que necesite usar Swift Code en proyectos Legacy escritos en Objective-C.
Ejemplo:
contentType.filename. Encadenar()
devuelve "nombre de archivo"
contentType.filename. valor bruto
devuelve el valor Int, 1 (ya que es el segundo elemento en struct)
@objc enum contentType:Int {
//date when content was created [RFC2183]
case creationDate
//name to be used when creating file [RFC2183]
case filename
//whether or not processing is required [RFC3204]
case handling
//date when content was last modified [RFC2183]
case modificationDate
//original field name in form [RFC7578]
case name
//Internet media type (and parameters) of the preview output desired from a processor by the author of the MIME content [RFC-ietf-appsawg-text-markdown-12]
case previewType
//date when content was last read [RFC2183]
case readDate
//approximate size of content in octets [RFC2183]
case size
//type or use of audio content [RFC2421]
case voice
func toString() -> String {
switch self {
case .creationDate:
return "creation-date"
case .filename:
return "filename"
case .handling:
return "handling"
case .modificationDate:
return "modification-date"
case .name:
return "name"
case .previewType:
return "preview-type"
case .readDate:
return "read-date"
case .size:
return "size"
case .voice:
return "voice"
}
}//eom
}//eo-enum
Aquí hay una solución plug-and-play que puede ampliar con una simple copia y pegue de sus definiciones EXISTENTES.
Espero que todos ustedes lo encuentren útil, ya que he encontrado útiles muchas otras soluciones de .
- (NSString*) enumItemNameForPrefix:(NSString*)enumPrefix item:(int)enumItem {
NSString* enumList = nil;
if ([enumPrefix isEqualToString:@"[Add Your Enum Name Here"]) {
// Instructions:
// 1) leave all code as is (it''s good reference and won''t conflict)
// 2) add your own enums below as follows:
// 2.1) duplicate the LAST else block below and add as many enums as you like
// 2.2) Copy then Paste your list, including carraige returns
// 2.3) add a back slash at the end of each line to concatenate the broken string
// 3) your are done.
}
else if ([enumPrefix isEqualToString:@"ExampleNonExplicitType"]) {
enumList = @" /
ExampleNonExplicitTypeNEItemName1, /
ExampleNonExplicitTypeNEItemName2, /
ExampleNonExplicitTypeNEItemName3 /
";
}
else if ([enumPrefix isEqualToString:@"ExampleExplicitAssignsType"]) {
enumList = @" /
ExampleExplicitAssignsTypeEAItemName1 = 1, /
ExampleExplicitAssignsTypeEAItemName2 = 2, /
ExampleExplicitAssignsTypeEAItemName3 = 4 /
";
}
else if ([enumPrefix isEqualToString:@"[Duplicate and Add Your Enum Name Here #1"]) {
// Instructions:
// 1) duplicate this else block and add as many enums as you like
// 2) Paste your list, including carraige returns
// 3) add a back slash at the end of each line to continue/concatenate the broken string
enumList = @" /
[Replace only this line: Paste your Enum Definition List Here] /
";
}
// parse it
int implicitIndex = 0;
NSString* itemKey = nil;
NSString* itemValue = nil;
NSArray* enumArray = [enumList componentsSeparatedByString:@","];
NSMutableDictionary* enumDict = [[[NSMutableDictionary alloc] initWithCapacity:enumArray.count] autorelease];
for (NSString* itemPair in enumArray) {
NSArray* itemPairArray = [itemPair componentsSeparatedByString:@"="];
itemValue = [[itemPairArray objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
itemKey = [NSString stringWithFormat:@"%d", implicitIndex];
if (itemPairArray.count > 1)
itemKey = [[itemPairArray lastObject] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
[enumDict setValue:itemValue forKey:itemKey];
implicitIndex++;
}
// return value with or without prefix
NSString* withPrefix = [enumDict valueForKey:[NSString stringWithFormat:@"%d", enumItem]];
NSString* withoutPrefix = [withPrefix stringByReplacingOccurrencesOfString:enumPrefix withString:@""];
NSString* outValue = (0 ? withPrefix : withoutPrefix);
if (0) NSLog(@"enum:%@ item:%d retVal:%@ dict:%@", enumPrefix, enumItem, outValue, enumDict);
return outValue;
}
Aquí están las declaraciones de ejemplo:
typedef enum _type1 {
ExampleNonExplicitTypeNEItemName1,
ExampleNonExplicitTypeNEItemName2,
ExampleNonExplicitTypeNEItemName3
} ExampleNonExplicitType;
typedef enum _type2 {
ExampleExplicitAssignsTypeEAItemName1 = 1,
ExampleExplicitAssignsTypeEAItemName2 = 2,
ExampleExplicitAssignsTypeEAItemName3 = 4
} ExampleExplicitAssignsType;
Aquí hay una llamada de ejemplo:
NSLog(@"EXAMPLE: type1:%@ type2:%@ ", [self enumItemNameForPrefix:@"ExampleNonExplicitType" item:ExampleNonExplicitTypeNEItemName2], [self enumItemNameForPrefix:@"ExampleExplicitAssignsType" item:ExampleExplicitAssignsTypeEAItemName3]);
¡Disfrutar! ;-)
En algunos casos, cuando necesita convertir enum -> NSString y NSString -> enumerar, podría ser más simple usar un typedef y #define (o const NSStrings) en lugar de enum:
typedef NSString * ImageType;
#define ImageTypeJpg @"JPG"
#define ImageTypePng @"PNG"
#define ImageTypeGif @"GIF"
y luego solo opere con cadenas "con nombre" como con cualquier otra cadena NSS:
@interface MyData : NSObject
@property (copy, nonatomic) ImageType imageType;
@end
@implementation MyData
- (void)doSomething {
//...
self.imageType = ImageTypePng;
//...
if ([self.imageType isEqualToString:ImageTypeJpg]) {
//...
}
}
@end
Encontré este website (del cual se toma el siguiente ejemplo) que proporciona una solución elegante a este problema. Sin embargo, la publicación original proviene de esta respuesta de .
// Place this in your .h file, outside the @interface block
typedef enum {
JPG,
PNG,
GIF,
PVR
} kImageType;
#define kImageTypeArray @"JPEG", @"PNG", @"GIF", @"PowerVR", nil
...
// Place this in the .m file, inside the @implementation block
// A method to convert an enum to string
-(NSString*) imageTypeEnumToString:(kImageType)enumVal
{
NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
return [imageTypeArray objectAtIndex:enumVal];
}
// A method to retrieve the int value from the NSArray of NSStrings
-(kImageType) imageTypeStringToEnum:(NSString*)strVal
{
NSArray *imageTypeArray = [[NSArray alloc] initWithObjects:kImageTypeArray];
NSUInteger n = [imageTypeArray indexOfObject:strVal];
if(n < 1) n = JPG;
return (kImageType) n;
}
Esta es una vieja pregunta, pero si tienes una enumeración no contigua utiliza un literal de diccionario en lugar de una matriz:
typedef enum {
value1 = 0,
value2 = 1,
value3 = 2,
// beyond value3
value1000 = 1000,
value1001
} MyType;
#define NSStringFromMyType( value ) /
( /
@{ /
@( value1 ) : @"value1", /
@( value2 ) : @"value2", /
@( value3 ) : @"value3", /
@( value1000 ) : @"value1000", /
@( value1001 ) : @"value1001", /
} /
[ @( value ) ] /
)
Esto es similar a la macro "publicación" por píxel. gracias por el enlace a http://en.wikipedia.org/wiki/X_Macro
El código generado en macros puede ser complicado y difícil de depurar. En su lugar, genere una tabla que sea usada por el código "normal". Encuentro que muchas personas se oponen a que las macros generen código, y puede ser una de las razones por las que la técnica de "X Macros" tal como se presenta en el wiki no es ampliamente adoptada.
Al generar una tabla, solo necesita editar un lugar para extender la lista, y como no puede "atravesar" una tabla en el depurador, esto elimina la objeción de muchas personas acerca de las líneas múltiples de código oculto en las macros.
//------------------------------------------------------------------------------
// enum to string example
#define FOR_EACH_GENDER(tbd) /
tbd(GENDER_MALE) /
tbd(GENDER_FEMALE) /
tbd(GENDER_INTERSEX) /
#define ONE_GENDER_ENUM(name) name,
enum
{
FOR_EACH_GENDER(ONE_GENDER_ENUM)
MAX_GENDER
};
#define ONE_GENDER(name) #name,
static const char *enumGENDER_TO_STRING[] =
{
FOR_EACH_GENDER(ONE_GENDER)
};
// access string name with enumGENDER_TO_STRING[value]
// or, to be safe converting from a untrustworthy caller
static const char *enumGenderToString(unsigned int value)
{
if (value < MAX_GENDER)
{
return enumGENDER_TO_STRING[value];
}
return NULL;
}
static void printAllGenders(void)
{
for (int ii = 0; ii < MAX_GENDER; ii++)
{
printf("%d) gender %s/n", ii, enumGENDER_TO_STRING[ii]);
}
}
//------------------------------------------------------------------------------
// you can assign an arbitrary value and/or information to each enum,
#define FOR_EACH_PERSON(tbd) /
tbd(2, PERSON_FRED, "Fred", "Weasley", GENDER_MALE, 12) /
tbd(4, PERSON_GEORGE, "George", "Weasley", GENDER_MALE, 12) /
tbd(6, PERSON_HARRY, "Harry", "Potter", GENDER_MALE, 10) /
tbd(8, PERSON_HERMIONE, "Hermione", "Granger", GENDER_FEMALE, 10) /
#define ONE_PERSON_ENUM(value, ename, first, last, gender, age) ename = value,
enum
{
FOR_EACH_PERSON(ONE_PERSON_ENUM)
};
typedef struct PersonInfoRec
{
int value;
const char *ename;
const char *first;
const char *last;
int gender;
int age;
} PersonInfo;
#define ONE_PERSON_INFO(value, ename, first, last, gender, age) /
{ ename, #ename, first, last, gender, age },
static const PersonInfo personInfo[] =
{
FOR_EACH_PERSON(ONE_PERSON_INFO)
{ 0, NULL, NULL, NULL, 0, 0 }
};
// note: if the enum values are not sequential, you need another way to lookup
// the information besides personInfo[ENUM_NAME]
static void printAllPersons(void)
{
for (int ii = 0; ; ii++)
{
const PersonInfo *pPI = &personInfo[ii];
if (!pPI->ename)
{
break;
}
printf("%d) enum %-15s %8s %-8s %13s %2d/n",
pPI->value, pPI->ename, pPI->first, pPI->last,
enumGenderToString(pPI->gender), pPI->age);
}
}
Esto se responde aquí: algunas sugerencias sobre la implementación
La línea de fondo es Objective-C
está usando una C
enum
normal, antigua, que es solo un conjunto glorificado de enteros.
Dada una enum
como esta:
typedef enum { a, b, c } FirstThreeAlpha;
Su método se vería así:
- (NSString*) convertToString:(FirstThreeAlpha) whichAlpha {
NSString *result = nil;
switch(whichAlpha) {
case a:
result = @"a";
break;
case b:
result = @"b";
break;
case c:
result = @"c";
break;
default:
result = @"unknown";
}
return result;
}
Esto será validado por el compilador, por lo que no confundirá los índices accidentalmente.
NSDictionary *stateStrings =
@{
@(MCSessionStateNotConnected) : @"MCSessionStateNotConnected",
@(MCSessionStateConnecting) : @"MCSessionStateConnecting",
@(MCSessionStateConnected) : @"MCSessionStateConnected",
};
NSString *stateString = [stateStrings objectForKey:@(state)];
var stateStrings: [MCSessionState: String] = [
MCSessionState.NotConnected : "MCSessionState.NotConnected",
MCSessionState.Connecting : "MCSessionState.Connecting",
MCSessionState.Connected : "MCSessionState.Connected"
]
var stateString = stateStrings[MCSessionState.Connected]
La siguiente solución utiliza el operador de cordaje del preprocesador, lo que permite una solución más elegante. Te permite definir los términos enum en un solo lugar para una mayor resistencia contra los errores tipográficos.
Primero, defina su enumeración de la siguiente manera.
#define ENUM_TABLE /
X(ENUM_ONE), /
X(ENUM_TWO) /
#define X(a) a
typedef enum Foo {
ENUM_TABLE
} MyFooEnum;
#undef X
#define X(a) @#a
NSString * const enumAsString[] = {
ENUM_TABLE
};
#undef X
Ahora, úsalo de la siguiente manera:
// Usage
MyFooEnum t = ENUM_ONE;
NSLog(@"Enum test - t is: %@", enumAsString[t]);
t = ENUM_TWO;
NSLog(@"Enum test - t is now: %@", enumAsString[t]);
qué salidas:
2014-10-22 13:36:21.344 FooProg[367:60b] Enum test - t is: ENUM_ONE
2014-10-22 13:36:21.344 FooProg[367:60b] Enum test - t is now: ENUM_TWO
La respuesta de @ pixel me indicó la dirección correcta.
No me gusta poner la enumeración en el montón, sin proporcionar una función de montón para la traducción. Esto es lo que se me ocurrió:
typedef enum {value1, value2, value3} myValue;
#define myValueString(enum) [@[@"value1",@"value2",@"value3"] objectAtIndex:enum]
Esto mantiene las declaraciones de cadena y enum juntas para facilitar la actualización cuando sea necesario.
Ahora, en cualquier parte del código, puede usar la enumeración / macro de esta manera:
myValue aVal = value2;
NSLog(@"The enum value is ''%@''.", myValueString(aVal));
outputs: The enum value is ''value2''.
Para garantizar los índices de los elementos, siempre puede declarar explícitamente los valores enum de inicio (o todos).
enum {value1=0, value2=1, value3=2};
Podría usar macros X, son perfectos para esto.
Beneficios 1. la relación entre el valor real de la enumeración y el valor de la cadena está en un lugar. 2. puede usar declaraciones de cambio regulares más adelante en su código.
Detrimento 1. El código de configuración inicial es un poco obtuso y utiliza macros divertidas.
El código
#define X(a, b, c) a b,
enum ZZObjectType {
ZZOBJECTTYPE_TABLE
};
typedef NSUInteger TPObjectType;
#undef X
#define XXOBJECTTYPE_TABLE /
X(ZZObjectTypeZero, = 0, "ZZObjectTypeZero") /
X(ZZObjectTypeOne, = 1, "ZZObjectTypeOne") /
X(ZZObjectTypeTwo, = 2, "ZZObjectTypeTwo") /
X(ZZObjectTypeThree, = 3, "ZZObjectTypeThree") /
+ (NSString*)nameForObjectType:(ZZObjectType)objectType {
#define X(a, b, c) @c, [NSNumber numberWithInteger:a],
NSDictionary *returnValue = [NSDictionary dictionaryWithObjectsAndKeys:ZZOBJECTTYPE_TABLE nil];
#undef X
return [returnValue objectForKey:[NSNumber numberWithInteger:objectType]];
}
+ (ZZObjectType)objectTypeForName:(NSString *)objectTypeString {
#define X(a, b, c) [NSNumber numberWithInteger:a], @c,
NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:ZZOBJECTSOURCE_TABLE nil];
#undef X
NSUInteger value = [(NSNumber *)[dictionary objectForKey:objectTypeString] intValue];
return (ZZObjectType)value;
}
Ahora puedes hacer:
NSString *someString = @"ZZObjectTypeTwo"
ZZObjectType objectType = [[XXObject objectTypeForName:someString] intValue];
switch (objectType) {
case ZZObjectTypeZero:
//
break;
case ZZObjectTypeOne:
//
break;
case ZZObjectTypeTwo:
//
break;
}
Este patrón ha existido desde los años 60 (¡no es broma!): http://en.wikipedia.org/wiki/X_Macro
Presentaré es la forma en que uso, y se ve mejor que la respuesta anterior. (Creo)
Me gustaría ilustrar con UIImageOrientation para una fácil comprensión.
typedef enum {
UIImageOrientationUp = 0, // default orientation, set to 0 so that it always starts from 0
UIImageOrientationDown, // 180 deg rotation
UIImageOrientationLeft, // 90 deg CCW
UIImageOrientationRight, // 90 deg CW
UIImageOrientationUpMirrored, // as above but image mirrored along other axis. horizontal flip
UIImageOrientationDownMirrored, // horizontal flip
UIImageOrientationLeftMirrored, // vertical flip
UIImageOrientationRightMirrored, // vertical flip
} UIImageOrientation;
crea un método como:
NSString *stringWithUIImageOrientation(UIImageOrientation input) {
NSArray *arr = @[
@"UIImageOrientationUp", // default orientation
@"UIImageOrientationDown", // 180 deg rotation
@"UIImageOrientationLeft", // 90 deg CCW
@"UIImageOrientationRight", // 90 deg CW
@"UIImageOrientationUpMirrored", // as above but image mirrored along other axis. horizontal flip
@"UIImageOrientationDownMirrored", // horizontal flip
@"UIImageOrientationLeftMirrored", // vertical flip
@"UIImageOrientationRightMirrored", // vertical flip
];
return (NSString *)[arr objectAtIndex:input];
}
Todo lo que tienes que hacer es :
nombra tu función.
copie el contenido de enum y pegue eso entre NSArray * arr = @ [ and ]; return (NSString *) [arr objectAtIndex: entrada];
poner algunos @, ", y coma
¡¡¡¡LUCRO!!!!
Si puedo ofrecer otra solución que tenga el beneficio adicional de verificar el tipo, advierta si le falta un valor enum en su conversión, legibilidad y brevedad.
Para su ejemplo dado: typedef enum { value1, value2, value3 } myValue;
Puedes hacerlo:
NSString *NSStringFromMyValue(myValue type) {
const char* c_str = 0;
#define PROCESS_VAL(p) case(p): c_str = #p; break;
switch(type) {
PROCESS_VAL(value1);
PROCESS_VAL(value2);
PROCESS_VAL(value3);
}
#undef PROCESS_VAL
return [NSString stringWithCString:c_str encoding:NSASCIIStringEncoding];
}
Como nota al margen. Es un mejor enfoque para declarar tus enumeraciones así:
typedef NS_ENUM(NSInteger, MyValue) {
Value1 = 0,
Value2,
Value3
}
Con esto obtienes seguridad de tipo ( NSInteger
en este caso), estableces el offset enum esperado ( = 0
).
Aquí está el código de trabajo https://github.com/ndpiparava/ObjcEnumString
//1st Approach
#define enumString(arg) (@""#arg)
//2nd Approach
+(NSString *)secondApproach_convertEnumToString:(StudentProgressReport)status {
char *str = calloc(sizeof(kgood)+1, sizeof(char));
int goodsASInteger = NSSwapInt((unsigned int)kgood);
memcpy(str, (const void*)&goodsASInteger, sizeof(goodsASInteger));
NSLog(@"%s", str);
NSString *enumString = [NSString stringWithUTF8String:str];
free(str);
return enumString;
}
//Third Approcah to enum to string
NSString *const kNitin = @"Nitin";
NSString *const kSara = @"Sara";
typedef NS_ENUM(NSUInteger, Name) {
NameNitin,
NameSara,
};
+ (NSString *)thirdApproach_convertEnumToString :(Name)weekday {
__strong NSString **pointer = (NSString **)&kNitin;
pointer +=weekday;
return *pointer;
}