可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have an enum holding several values:
enum {value1, value2, value3} myValue;
In a certain point in my app, I wish to check which value of the enum is now active. I'm using NSLog but I'm not clear on how to display the current value of the enum (value1/valu2/valu3/etc...) as a NSString for the NSLog.
Anyone?
回答1:
This is answered here: a few suggestions on implementation
The bottom line is Objective-C
is using a regular, old C
enum
, which is just a glorified set of integers.
Given an enum
like this:
typedef enum { a, b, c } FirstThreeAlpha;
Your method would look like this:
- (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;
}
回答2:
I didn't like putting the enum on the heap, without providing a heap function for translation. Here's what I came up with:
typedef enum {value1, value2, value3} myValue;
#define myValueString(enum) [@[@"value1",@"value2",@"value3"] objectAtIndex:enum]
This keeps the enum and string declarations close together for easy updating when needed.
Now, anywhere in the code, you can use the enum/macro like this:
myValue aVal = value2;
NSLog(@"The enum value is '%@'.", myValueString(aVal));
outputs: The enum value is 'value2'.
To guarantee the element indexes, you can always explicitly declare the start(or all) enum values.
enum {value1=0, value2=1, value3=2};
回答3:
I will introduce is the way I use, and it looks better than previous answer.(I thinks)
I would like to illustrate with UIImageOrientation for easy understanding.
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;
create a method like:
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];
}
All you have to do is :
name your function.
copy contents of enum and paste that between NSArray *arr = @[ and ]; return (NSString *)[arr objectAtIndex:input];
put some @ , " , and comma
PROFIT!!!!
回答4:
This will be validated by compiler, so you won't mix up indices accidentally.
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]
回答5:
I found this website (from which the example below is taken) which provides an elegant solution to this problem. The original posting though comes from this StackOverflow answer.
// 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;
}
回答6:
If I can offer another solution that has the added benefit of type checking, warnings if you are missing an enum value in your conversion, readability, and brevity.
For your given example: typedef enum { value1, value2, value3 } myValue;
you can do this:
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];
}
As a side note. It is a better approach to declare your enums as so:
typedef NS_ENUM(NSInteger, MyValue) {
Value1 = 0,
Value2,
Value3
}
With this you get type-safety (NSInteger
in this case), you set the expected enum offset (= 0
).
回答7:
In some cases when you need to convert enum -> NSString and NSString -> enum it might be simpler to use a typedef and #define (or const NSStrings) instead of enum:
typedef NSString * ImageType;
#define ImageTypeJpg @"JPG"
#define ImageTypePng @"PNG"
#define ImageTypeGif @"GIF"
and then just operate with "named" strings as with any other NSString:
@interface MyData : NSObject
@property (copy, nonatomic) ImageType imageType;
@end
@implementation MyData
- (void)doSomething {
//...
self.imageType = ImageTypePng;
//...
if ([self.imageType isEqualToString:ImageTypeJpg]) {
//...
}
}
@end
回答8:
The solution below uses the preprocessor's stringize operator, allowing for a more elegant solution. It lets you define the enum terms in just one place for greater resilience against typos.
First, define your enum in the following way.
#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
Now, use it in the following way:
// Usage
MyFooEnum t = ENUM_ONE;
NSLog(@"Enum test - t is: %@", enumAsString[t]);
t = ENUM_TWO;
NSLog(@"Enum test - t is now: %@", enumAsString[t]);
which outputs:
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
@pixel's answer pointed me in the right direction.
回答9:
You could use X macros - they are perfect for this.
Benefits
1. the relationship between the actual enum value and the string value is in one place.
2. you can use regular switch statements later in your code.
Detriment
1. The initial setup code is a bit obtuse, and uses fun macros.
The code
#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;
}
Now you can do:
NSString *someString = @"ZZObjectTypeTwo"
ZZObjectType objectType = [[XXObject objectTypeForName:someString] intValue];
switch (objectType) {
case ZZObjectTypeZero:
//
break;
case ZZObjectTypeOne:
//
break;
case ZZObjectTypeTwo:
//
break;
}
This pattern has been around since the 1960's (no kidding!): http://en.wikipedia.org/wiki/X_Macro
回答10:
Here is a plug-and-play solution that you can extend with a simple copy and paste of your EXISTING definitions.
I hope you all find it useful, as I have found useful so many other StackOverflow solutions.
- (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;
}
Here are the example declarations:
typedef enum _type1 {
ExampleNonExplicitTypeNEItemName1,
ExampleNonExplicitTypeNEItemName2,
ExampleNonExplicitTypeNEItemName3
} ExampleNonExplicitType;
typedef enum _type2 {
ExampleExplicitAssignsTypeEAItemName1 = 1,
ExampleExplicitAssignsTypeEAItemName2 = 2,
ExampleExplicitAssignsTypeEAItemName3 = 4
} ExampleExplicitAssignsType;
Here is an example call:
NSLog(@"EXAMPLE: type1:%@ type2:%@ ", [self enumItemNameForPrefix:@"ExampleNonExplicitType" item:ExampleNonExplicitTypeNEItemName2], [self enumItemNameForPrefix:@"ExampleExplicitAssignsType" item:ExampleExplicitAssignsTypeEAItemName3]);
Enjoy!
;-)
回答11:
Below is a example of Enum Struct that is Objective-C friendly in the event you need to use Swift Code in Legacy projects written in Objective-C.
Example:
contentType.filename. toString()
returns "filename"
contentType.filename. rawValue
returns the Int Value, 1 (since its the second item on 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
回答12:
This is an old question, but if you have a non contiguous enum use a dictionary literal instead of an array:
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 ) ] \
)
回答13:
Suppose requirement is to enumerate list of languages.
Add this to .h file
typedef NS_ENUM(NSInteger, AvailableLanguage) {
ENGLISH,
GERMAN,
CHINENSE
};
Now, in .m file simply create an array like,
// Try to use the same naming convention throughout.
// That is, adding ToString after NS_ENUM name;
NSString* const AvailableLanguageToString[] = {
[ENGLISH] = @"English",
[GERMAN] = @"German",
[CHINESE] = @"Chinese"
};
Thats it. Now you can use enum with easy and get string for enums using array. For example,
- (void) setPreferredLanguage:(AvailableLanguage)language {
// this will get the NSString* for the language.
self.preferredLanguage = AvailableLanguageToString[language];
}
Thus, this pattern depends on accepted naming convention of NS_ENUM and companion ToString array. Try to follow this convention through out and it will become natural.
回答14:
This is similar to the "X" macro post by pixel.
thanks for the link to http://en.wikipedia.org/wiki/X_Macro
Code generated in macros can be tricky and hard to debug.
Instead, generate a table that is used by "normal" code.
I find that many people object to having macros generate code,
and may be one reason the technique of "X Macros" as presented
in the wiki is not widely adopted.
By generating a table, you still need only edit one place to extend the list,
and since you can't "step through" a table in the debugger, this removes the
objection from many people about multi-lines of code buried in 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);
}
}
回答15:
a macro:
#define stringWithLiteral(literal) @#literal
an enum:
typedef NS_ENUM(NSInteger, EnumType) {
EnumType0,
EnumType1,
EnumType2
};
an array:
static NSString * const EnumTypeNames[] = {
stringWithLiteral(EnumType0),
stringWithLiteral(EnumType1),
stringWithLiteral(EnumType2)
};
using:
EnumType enumType = ...;
NSString *enumName = EnumTypeNames[enumType];
==== EDIT ====
Copy the following code to your project and run.
#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);
}
回答16:
Here is working code
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;
}