いくつかの値を保持する列挙型があります:
enum {value1、value2、value3} myValue;
アプリの特定の時点で、enumのどの値が現在アクティブになっているかを確認したいと思います。 NSLogを使用していますが、enumの現在の値(value1/valu2/valu3/etc ...)をNSLogのNSStringとして表示する方法が明確ではありません。
誰でも?
これはここに答えられます: 実装に関するいくつかの提案
一番下の行はObjective-C
は、通常の古いC
enum
を使用しています。これは単なる整数の栄光のセットです。
このようなenum
が与えられた場合:
typedef enum { a, b, c } FirstThreeAlpha;
メソッドは次のようになります。
- (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;
}
翻訳用のヒープ関数を提供せずに、enumをヒープに配置するのは好きではありませんでした。ここに私が思いついたものがあります:
typedef enum {value1, value2, value3} myValue;
#define myValueString(enum) [@[@"value1",@"value2",@"value3"] objectAtIndex:enum]
これにより、必要なときに簡単に更新できるように、列挙と文字列の宣言を密接に保ちます。
これで、コードのどこでも、次のように列挙型/マクロを使用できます。
myValue aVal = value2;
NSLog(@"The enum value is '%@'.", myValueString(aVal));
outputs: The enum value is 'value2'.
要素のインデックスを保証するために、start(またはすべて)列挙値を常に明示的に宣言できます。
enum {value1=0, value2=1, value3=2};
私が紹介するのは私が使用する方法であり、前の答えよりも良く見えます(私は思う)
で説明したいと思います UIImageOrientation 理解しやすいように。
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;
次のようなメソッドを作成します。
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];
}
あなたがしなければならないのは:
関数に名前を付けます。
enumの内容をコピーし、その間に貼り付けます NSArray * arr = @ [ そして ]; return(NSString *)[arr objectAtIndex:input];
@、 "、およびコンマを入れます
利益!!!!
これはコンパイラによって検証されるため、誤ってインデックスを混同することはありません。
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]
私はこれを見つけました website (以下の例から)この問題に対するエレガントな解決策を提供します。ただし、元の投稿はこれに基づいています 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;
}
場合によっては、enum-> NSStringおよびNSString-> enumを変換する必要がある場合、enumの代わりにtypedefおよび#define(またはconst NSStrings)を使用する方が簡単な場合があります。
typedef NSString * ImageType;
#define ImageTypeJpg @"JPG"
#define ImageTypePng @"PNG"
#define ImageTypeGif @"GIF"
そして、他のNSStringと同様に「名前付き」文字列を操作するだけです。
@interface MyData : NSObject
@property (copy, nonatomic) ImageType imageType;
@end
@implementation MyData
- (void)doSomething {
//...
self.imageType = ImageTypePng;
//...
if ([self.imageType isEqualToString:ImageTypeJpg]) {
//...
}
}
@end
型チェック、変換、読みやすさ、簡潔さの列挙値が欠落している場合の警告の追加の利点を持つ別のソリューションを提供できる場合。
与えられた例:typedef enum { value1, value2, value3 } myValue;
あなたはこれを行うことができます:
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];
}
補足として。列挙型を次のように宣言するのがより良い方法です。
typedef NS_ENUM(NSInteger, MyValue) {
Value1 = 0,
Value2,
Value3
}
これにより、タイプセーフ(この場合はNSInteger
)が得られ、予想される列挙オフセット(= 0
)。
以下のソリューションでは、プリプロセッサの文字列化演算子を使用して、より洗練されたソリューションを実現しています。タイプミスに対する回復力を高めるために、1か所で列挙語を定義できます。
まず、次の方法で列挙型を定義します。
#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
次に、次の方法で使用します。
// Usage
MyFooEnum t = ENUM_ONE;
NSLog(@"Enum test - t is: %@", enumAsString[t]);
t = ENUM_TWO;
NSLog(@"Enum test - t is now: %@", enumAsString[t]);
どの出力:
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の答えは正しい方向を示してくれました。
Swift Objective-Cで記述されたレガシープロジェクトのコードを使用する必要がある場合に、Objective-Cに適したEnum Structの例を次に示します。
例:
contentType.filename。 toString()
「ファイル名」を返します
contentType.filename。 rawValue
int値、1を返します(構造体の2番目の項目なので)
@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
これは古い質問ですが、連続していない列挙型がある場合は、配列ではなく辞書リテラルを使用します。
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 ) ] \
)
Xマクロを使用できます-これは完璧です。
Benefits1.実際の列挙値と文字列値の関係は1か所にあります。 2.コードの後半で通常のswitchステートメントを使用できます。
Detriment1.初期セットアップコードは少しわかりにくく、楽しいマクロを使用します。
コード
#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;
}
できるようになりました:
NSString *someString = @"ZZObjectTypeTwo"
ZZObjectType objectType = [[XXObject objectTypeForName:someString] intValue];
switch (objectType) {
case ZZObjectTypeZero:
//
break;
case ZZObjectTypeOne:
//
break;
case ZZObjectTypeTwo:
//
break;
}
このパターンは1960年代から存在します(冗談ではありません!): http://en.wikipedia.org/wiki/X_Macro
これは、既存の定義の簡単なコピーアンドペーストで拡張できるプラグアンドプレイソリューションです。
他の多くのStackOverflowソリューションが有用であることがわかったので、皆さんの役に立つことを願っています。
- (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;
}
宣言の例を次に示します。
typedef enum _type1 {
ExampleNonExplicitTypeNEItemName1,
ExampleNonExplicitTypeNEItemName2,
ExampleNonExplicitTypeNEItemName3
} ExampleNonExplicitType;
typedef enum _type2 {
ExampleExplicitAssignsTypeEAItemName1 = 1,
ExampleExplicitAssignsTypeEAItemName2 = 2,
ExampleExplicitAssignsTypeEAItemName3 = 4
} ExampleExplicitAssignsType;
呼び出しの例を次に示します。
NSLog(@"EXAMPLE: type1:%@ type2:%@ ", [self enumItemNameForPrefix:@"ExampleNonExplicitType" item:ExampleNonExplicitTypeNEItemName2], [self enumItemNameForPrefix:@"ExampleExplicitAssignsType" item:ExampleExplicitAssignsTypeEAItemName3]);
楽しい! ;-)
要件が言語のリストを列挙することであるとします。
これを.hファイルに追加します
typedef NS_ENUM(NSInteger, AvailableLanguage) {
ENGLISH,
GERMAN,
CHINENSE
};
さて、.mファイルに次のような配列を作成するだけです。
// 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"
};
それでおしまい。これで、enumをeasyで使用し、配列を使用してenumの文字列を取得できます。例えば、
- (void) setPreferredLanguage:(AvailableLanguage)language {
// this will get the NSString* for the language.
self.preferredLanguage = AvailableLanguageToString[language];
}
したがって、このパターンは、NS_ENUMおよび関連するToString配列の受け入れられている命名規則に依存します。この規則を最後まで従うようにしてください。そうすれば自然になります。
これは、ピクセルごとの「X」マクロの投稿に似ています。 http://en.wikipedia.org/wiki/X_Macro へのリンクをありがとう
マクロで生成されたコードは扱いにくく、デバッグが難しい場合があります。代わりに、「通常の」コードで使用されるテーブルを生成します。多くの人々がマクロにコードを生成させることに反対していることを発見しました。これは、Wikiで提示されている「Xマクロ」の手法が広く採用されていない理由の1つです。
テーブルを生成することで、リストを拡張するために1箇所だけ編集する必要があります。また、デバッガーでテーブルを「ステップスルー」できないため、マクロに埋め込まれた複数行のコードに関する多くの人々からの異議を取り除きます。
//------------------------------------------------------------------------------
// 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);
}
}
ここに作業コードがあります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;
}
マクロ:
#define stringWithLiteral(literal) @#literal
列挙型:
typedef NS_ENUM(NSInteger, EnumType) {
EnumType0,
EnumType1,
EnumType2
};
配列:
static NSString * const EnumTypeNames[] = {
stringWithLiteral(EnumType0),
stringWithLiteral(EnumType1),
stringWithLiteral(EnumType2)
};
を使用して:
EnumType enumType = ...;
NSString *enumName = EnumTypeNames[enumType];
====編集====
次のコードをプロジェクトにコピーして実行します。
#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);
}