Objective-Cのtypedefを同等の文字列に変換する


141

.hファイルでtypedefが宣言されていると仮定します。

typedef enum {
  JSON,
  XML,
  Atom,
  RSS
} FormatType;

typedefの数値を文字列に変換する関数を作成したいと思います。たとえば、メッセージ[self toString:JSON]が送信された場合。「JSON」を返します。

関数は次のようになります。

-(NSString *) toString:(FormatType)formatType {
  //need help here
  return [];
}

ちなみに、この構文を試してみると

[self toString:FormatType.JSON];

typedef値をメソッドに渡すと、エラーが発生します。何が欠けていますか?


この問題に対するより明確な解決策については、stackoverflow.com / questions / 6331762 / enum-values- to -nsstring-iosで私の回答を参照してください。
BooTooMany 2014年

4
たぶん、列挙型でSwift言語に抱擁を与える必要があります。
イタチ

@craig:ソリューションgithub.com/ndpiparava/ObjcEnumString
Nitin

文字列に変換する列挙型のカスタムゲッターを単に使用しないソリューションについては、文字列キャストマクロ配列を確認してください:stackoverflow.com/a/53755377/2057171
Albert Renshaw

回答:


135

これは実際にはCの質問であり、Objective-C(C言語のスーパーセット)に固有のものではありません。Cの列挙型は整数として表されます。したがって、列挙値を指定して文字列を返す関数を作成する必要があります。これを行うには多くの方法があります。enum値を配列へのインデックスとして使用できるような文字列の配列またはNSDictionaryenum値を文字列にマップするマップ構造(例:)ですが、これらのアプローチは、変換を明示的にしCます(列挙型の値が0から連続しない場合、古典的な方法は危険ですが)。このような何かがうまくいくでしょう:

- (NSString*)formatTypeToString:(FormatType)formatType {
    NSString *result = nil;

    switch(formatType) {
        case JSON:
            result = @"JSON";
            break;
        case XML:
            result = @"XML";
            break;
        case Atom:
            result = @"Atom";
            break;
        case RSS:
            result = @"RSS";
            break;
        default:
            [NSException raise:NSGenericException format:@"Unexpected FormatType."];
    }

    return result;
}

列挙値の正しい構文に関する関連する質問は、構文ではJSONなく値(たとえば)のみを使用することですFormatType.JSONFormatTypeタイプと列挙値(例えばさJSONXMLなど)を使用すると、そのタイプに割り当てることができる値です。


127

簡単にはできません。CおよびObjective-Cでは、列挙型は実際には美化された整数定数です。自分で名前のテーブルを生成する必要があります(または、プリプロセッサの乱用を伴う)。例えば:

// In a header file
typedef enum FormatType {
    JSON,
    XML,
    Atom,
    RSS
} FormatType;

extern NSString * const FormatType_toString[];

// In a source file
// initialize arrays with explicit indices to make sure 
// the string match the enums properly
NSString * const FormatType_toString[] = {
    [JSON] = @"JSON",
    [XML] = @"XML",
    [Atom] = @"Atom",
    [RSS] = @"RSS"
};
...
// To convert enum to string:
NSString *str = FormatType_toString[theEnumValue];

このアプローチの危険性は、列挙型を変更した場合、名前の配列を変更することを忘れないようにする必要があることです。この問題は、プリプロセッサの乱用で解決できますが、トリッキーで醜いです。

また、これは有効な列挙定数があることを前提としています。信頼できないソースからの整数値がある場合、たとえば、列挙に「過去の最大」値を含めるか、配列の長さよりも小さいかどうかを確認するなど、定数が有効であることを確認する必要がありますsizeof(FormatType_toString) / sizeof(FormatType_toString[0])


37
明示的なインデックスを使用して配列を初期化できます。たとえばstring[] = { [XML] = "XML" }、文字列が列挙型と適切に一致するようにします
Christoph

@Christoph:はい、これは指定イニシャライザと呼ばれるC99の機能です。Objective-C(C99に基づく)で使用するのは問題ありませんが、一般的なC89コードの場合は使用できません。
Adam Rosenfield

逆の方法はありますか?たとえば、文字列を指定して列挙型を取得しますか?
Jameo 2014

1
@Jameo:はい、しかし、それは配列ルックアップを行うほど簡単ではありません。FormatType_toString[]配列を反復処理して-isEqualToString:各要素を呼び出し、一致を見つけるかNSDictionary、逆ルックアップマップを維持するためなどにマッピングデータタイプを使用する必要があります。
Adam Rosenfield、2014

1
Max Oの秘訣は、FormatType_toString配列にエントリを追加するのを忘れることです。
AechoLiu

50

私の解決策:

編集:Modern Obj-Cを使用して、最後にさらに良い解決策を追加しました

1.
名前を配列としてキーとして入力します。
インデックスが適切な列挙型であり、正しい順序になっていることを確認してください(それ以外の場合は例外です)。
注:名前は* _names *として合成されたプロパティです。

コードのコンパイルはチェックされませんでしたが、アプリで同じテクニックを使用しました。

typedef enum {
  JSON,
  XML,
  Atom,
  RSS
} FormatType;

+ (NSArray *)names
{
    static NSMutableArray * _names = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _names = [NSMutableArray arrayWithCapacity:4];
        [_names insertObject:@"JSON" atIndex:JSON];
        [_names insertObject:@"XML" atIndex:XML];
        [_names insertObject:@"Atom" atIndex:Atom];
        [_names insertObject:@"RSS" atIndex:RSS];
    });

    return _names;
}

+ (NSString *)nameForType:(FormatType)type
{
    return [[self names] objectAtIndex:type];
}


//

2.
Modern Obj-Cを使用すると、辞書を使用して、列挙型のキーに説明を関連付けることができます。
注文は関係ありません

typedef NS_ENUM(NSUInteger, UserType) {
    UserTypeParent = 0,
    UserTypeStudent = 1,
    UserTypeTutor = 2,
    UserTypeUnknown = NSUIntegerMax
};  

@property (nonatomic) UserType type;

+ (NSDictionary *)typeDisplayNames
{
    return @{@(UserTypeParent) : @"Parent",
             @(UserTypeStudent) : @"Student",
             @(UserTypeTutor) : @"Tutor",
             @(UserTypeUnknown) : @"Unknown"};
}

- (NSString *)typeDisplayName
{
    return [[self class] typeDisplayNames][@(self.type)];
}


使用法(クラスインスタンスメソッド内):

NSLog(@"%@", [self typeDisplayName]);



12
を呼び出すたびに+[typeDisplayNames]、辞書が再作成されることに注意してください。これは、数回しか呼び出されない場合は問題ありませんが、何度も呼び出される場合は、非常に高価になります。より良い解決策は、辞書をシングルトンにすることです。そのため、辞書は一度だけ作成され、それ以外の場合はメモリに残ります。クラシックメモリとCPUの難問。
ジョエル・フィッシャー

または、静的変数に変更します。たとえば、static NSDictionary *dict = nil; if(!dict) dict = @{@(UserTypeParent): @"Parent"}; return dict;コメントでは改行できません。申し訳ありません。
natanavra 2017年

29

@AdamRosenfieldの回答、@ Christophのコメント、および私が提案するプレーンなC列挙型を処理するための別のトリックを組み合わせる:

// In a header file
typedef enum {
  JSON = 0,         // explicitly indicate starting index
  XML,
  Atom,
  RSS,

  FormatTypeCount,  // keep track of the enum size automatically
} FormatType;
extern NSString *const FormatTypeName[FormatTypeCount];


// In a source file
NSString *const FormatTypeName[FormatTypeCount] = {
  [JSON] = @"JSON",
  [XML] = @"XML",
  [Atom] = @"Atom",
  [RSS] = @"RSS",
};


// Usage
NSLog(@"%@", FormatTypeName[XML]);

最悪の場合-enumを変更したが、names配列を変更し忘れた場合-このキーに対してnilを返します。


12

クラスヘッダーでtypedef enumを定義します。

typedef enum {
    IngredientType_text  = 0,
    IngredientType_audio = 1,
    IngredientType_video = 2,
    IngredientType_image = 3
} IngredientType;

次のようなメソッドをクラスに記述します。

+ (NSString*)typeStringForType:(IngredientType)_type {
   NSString *key = [NSString stringWithFormat:@"IngredientType_%i", _type];
   return NSLocalizedString(key, nil);
}

Localizable.stringsファイル内に文字列があります。

/* IngredientType_text */
"IngredientType_0" = "Text";
/* IngredientType_audio */
"IngredientType_1" = "Audio";
/* IngredientType_video */
"IngredientType_2" = "Video";
/* IngredientType_image */
"IngredientType_3" = "Image";

11

私はコンパイラーの#文字列トークンを使用します(すべてコンパクトにするためにマクロと一緒に):

#define ENUM_START              \
            NSString* ret;      \
            switch(value) {

#define ENUM_CASE(evalue)       \
            case evalue:        \
                ret = @#evalue; \
                break;

#define ENUM_END                \
            }                   \
            return ret;

NSString*
_CvtCBCentralManagerStateToString(CBCentralManagerState value)
{
    ENUM_START
        ENUM_CASE(CBCentralManagerStateUnknown)
        ENUM_CASE(CBCentralManagerStateResetting)
        ENUM_CASE(CBCentralManagerStateUnsupported)
        ENUM_CASE(CBCentralManagerStateUnauthorized)
        ENUM_CASE(CBCentralManagerStatePoweredOff)
        ENUM_CASE(CBCentralManagerStatePoweredOn)
    ENUM_END
}

これはC99でうまく機能しました-私はCの初心者です。そして、これが、尋ねられた質問を達成するための最もクリーンな方法であることがわかりました。また、定義されていない可能性のあるアイテムの実装にデフォルトを追加しました。とてもきれいな方法です。結果をありがとう。非常に巧妙なマクロの使用。
TravisWhidden 2016年

8

#defineはこれを行う方法が好きです:

//これを.hファイルの@interfaceブロックの外に配置します

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];
}

ソース(ソースは使用できなくなりました)


@ Daij-Djan戻りのnil場合はどうarray.count <= enumValueですか?
anneblue 2014年

エラーをキャッチする@anneblue .. enum値を追加したり、enum値の整数値を変更したりすると、これがうまくいかないため、脆弱になります。受け入れられた答えは良いでしょう
Daij-Djan

@codercat :(申し訳ありません-そのWebサイトで何が起こったのかわかりません。
途中で戻ってい

上記の答えについて少し質問があります。文字列要素をkImageTypeに変換する方法。文字列を渡してimageTypeEnumToStringメソッドを呼び出す必要があります。私の問題を解決するために手伝ってください。
ガネーシュ2014年

1
列挙型のすぐ隣に文字列定義があるので、私はこの答えが一番好きです。値が欠落する可能性が最も低い。そして、@ Ganeshは、生の値から変換するために、これを行うことができます:return(kImageType)[imageTypeArray indexOfObject:rawValue];
Harris

8

私はこのページにあるすべてのソリューションを組み合わせて私のものを作成しました。それは一種のオブジェクト指向の列挙型拡張か何かです。

実際、定数(つまり、整数)以外のものが必要な場合は、おそらくモデルオブジェクトが必要です(私たち全員がMVCについて話していますよね?)

これを使用する前に自分自身に質問してください、そうですか、実際には、Webサービス、plist、SQLiteデータベース、またはCoreDataから初期化された実際のモデルオブジェクトが必要ですか?

とにかくここにコードがあります(MPIは "My Project Initials"の略です。誰もがこれまたは自分の名前を使用しているようです)。

MyWonderfulType.h

typedef NS_ENUM(NSUInteger, MPIMyWonderfulType) {
    MPIMyWonderfulTypeOne = 1,
    MPIMyWonderfulTypeTwo = 2,
    MPIMyWonderfulTypeGreen = 3,
    MPIMyWonderfulTypeYellow = 4,
    MPIMyWonderfulTypePumpkin = 5
};

#import <Foundation/Foundation.h>

@interface MyWonderfulType : NSObject

+ (NSString *)displayNameForWonderfulType:(MPIMyWonderfulType)wonderfulType;
+ (NSString *)urlForWonderfulType:(MPIMyWonderfulType)wonderfulType;

@end

そしてMyWonderfulType.m

#import "MyWonderfulType.h"

@implementation MyWonderfulType

+ (NSDictionary *)myWonderfulTypeTitles
{
    return @{
             @(MPIMyWonderfulTypeOne) : @"One",
             @(MPIMyWonderfulTypeTwo) : @"Two",
             @(MPIMyWonderfulTypeGreen) : @"Green",
             @(MPIMyWonderfulTypeYellow) : @"Yellow",
             @(MPIMyWonderfulTypePumpkin) : @"Pumpkin"
             };
}

+ (NSDictionary *)myWonderfulTypeURLs
{
    return @{
             @(MPIMyWonderfulTypeOne) : @"http://www.theone.com",
             @(MPIMyWonderfulTypeTwo) : @"http://www.thetwo.com",
             @(MPIMyWonderfulTypeGreen) : @"http://www.thegreen.com",
             @(MPIMyWonderfulTypeYellow) : @"http://www.theyellow.com",
             @(MPIMyWonderfulTypePumpkin) : @"http://www.thepumpkin.com"
             };
}

+ (NSString *)displayNameForWonderfulType:(MPIMyWonderfulType)wonderfulType {
    return [MPIMyWonderfulType myWonderfulTypeTitles][@(wonderfulType)];
}

+ (NSString *)urlForWonderfulType:(MPIMyWonderfulType)wonderfulType {
    return [MPIMyWonderfulType myWonderfulTypeURLs][@(wonderfulType)];
}


@end

見栄えは良いですが、値の1つだけが必要なときに、完全な辞書を割り当てて返します。効率VS Prettyコード?あなたが何をしたいかに依存し、巨大なループのようにあなたのコードでそれらをあまり使用しなければ、これで問題ありません。しかし、これは、たとえばサーバーからの「動的」またはハードコードされていない列挙型で役立つ場合があります
user2387149

5

別の解決策:

typedef enum BollettinoMavRavTypes {
    AMZCartServiceOperationCreate,
    AMZCartServiceOperationAdd,
    AMZCartServiceOperationGet,
    AMZCartServiceOperationModify
} AMZCartServiceOperation;

#define AMZCartServiceOperationValue(operation) [[[NSArray alloc] initWithObjects: @"CartCreate", @"CartAdd", @"CartGet", @"CartModify", nil] objectAtIndex: operation];

あなたの方法ではあなたが使うことができます:

NSString *operationCheck = AMZCartServiceOperationValue(operation);

4

文字列の依存関係を削除することにより、@ yar1vnの回答を改善しました。

#define VariableName(arg) (@""#arg)

typedef NS_ENUM(NSUInteger, UserType) {
    UserTypeParent = 0,
    UserTypeStudent = 1,
    UserTypeTutor = 2,
    UserTypeUnknown = NSUIntegerMax
};  

@property (nonatomic) UserType type;

+ (NSDictionary *)typeDisplayNames
{
    return @{@(UserTypeParent) : VariableName(UserTypeParent),
             @(UserTypeStudent) : VariableName(UserTypeStudent),
             @(UserTypeTutor) : VariableName(UserTypeTutor),
             @(UserTypeUnknown) : VariableName(UserTypeUnknown)};
}

- (NSString *)typeDisplayName
{
    return [[self class] typeDisplayNames][@(self.type)];
}

したがって、enumエントリ名を変更すると、対応する文字列が変更されます。この文字列をユーザーに表示しない場合に役立ちます。


"
-define

#definesでは、置換に#を使用すると、引数は自動的に二重引用符で囲まれます。Cでは、2つの文字列がのようなコードで隣り合って現れる場合、コンパイル時に"foo""bar"文字列"foobar"になります。したがって、#define VariableName(arg) (@""#arg)に展開さVariableName(MyEnum)れます(@"""MyEnum")。その結果、文字列になります@"MyEnum"
クリスダグラス2017

3

次のような列挙型の定義があるとします。

typedef NS_ENUM(NSInteger, AssetIdentifier) {
    Isabella,
    William,
    Olivia
};

以下に示すように、enum値を対応する文字列に変換するマクロを定義できます。

#define AssetIdentifier(asset) \
^(AssetIdentifier identifier) { \
switch (identifier) { \
case asset: \
default: \
return @#asset; \
} \
}(asset)

switchブロックで使用される文は、型チェックのためであり、またXcodeでオートコンプリートのサポートを取得します。

ここに画像の説明を入力してください ここに画像の説明を入力してください


2

私はそれをNSDictionaryルックアップに変換したい大きな列挙型を持っていました。私はsedOSX端末から次のように使用してしまいました:

$ sed -E 's/^[[:space:]]{1,}([[:alnum:]]{1,}).*$/  @(\1) : @"\1",/g' ObservationType.h

これは次のように読み取ることができます: '行の最初の単語をキャプチャして出力@(word):@ "word"、'

この正規表現は、以下を含む 'ObservationType.h'という名前のヘッダーファイルの列挙型を変換します。

typedef enum : int { 
    ObservationTypePulse = 1,
    ObservationTypeRespRate = 2,
    ObservationTypeTemperature = 3,
    .
    .
}

次のようなものに:

    @(ObservationTypePulse) : @"ObservationTypePulse",
    @(ObservationTypeRespRate) : @"ObservationTypeRespRate",
    @(ObservationTypeTemperature) : @"ObservationTypeTemperature",
    .
    .

次に、@{ }(上記の@ yar1vnで説明されているように)最新のObjective-C構文を使用してメソッドにラップし、NSDictionaryルックアップを作成できます。

-(NSDictionary *)observationDictionary
{
    static NSDictionary *observationDictionary;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        observationDictionary = [[NSDictionary alloc] initWithDictionary:@{
                                 @(ObservationTypePulse) : @"ObservationTypePulse",
                                 @(ObservationTypeRespRate) : @"ObservationTypeRespRate",
                                 .
                                 .
                                 }];
    });
    return observationDictionary;
}

dispatch_onceボイラープレートは、単に静的変数は、スレッドセーフな方法で初期化されることを保証することです。

注:OSXでsed正規表現が奇妙に見つかりました- +「1つ以上」に一致させるために使用しようとしたときに、機能せず{1,}、代替として使用する必要がありました


2

私はバリーウォークの回答のバリエーションを使用します。

  1. コンパイラが不足しているcase句をチェックできるようにします(デフォルトの句がある場合はチェックできません)。
  2. Javaのような名前ではなく、Objective-Cの一般的な名前を使用します。
  3. 特定の例外を発生させます。
  4. 短いです。

例えば:

- (NSString*)describeFormatType:(FormatType)formatType {    
    switch(formatType) {
        case JSON:
            return @"JSON";
        case XML:
            return @"XML";
        case Atom:
            return @"Atom";
        case RSS:
            return @"RSS";
    }
    [NSException raise:NSInvalidArgumentException format:@"The given format type number, %ld, is not known.", formatType];
    return nil; // Keep the compiler happy - does not understand above line never returns!
}

2

@pixelが最も素晴らしい答えをここに追加しました:https ://stackoverflow.com/a/24255387/1364257どうか、彼に賛成票を投じて ください!

彼は1960年代のきちんとしたXマクロを使用しています。(私は彼のコードを現代のObjCのために少し変更しました)

#define X(a, b, c) a b,
enum ZZObjectType {
    XXOBJECTTYPE_TABLE
};
typedef NSUInteger TPObjectType;
#undef X

#define XXOBJECTTYPE_TABLE \
X(ZZObjectTypeZero, = 0, @"ZZObjectTypeZero") \
X(ZZObjectTypeOne, , @"ZZObjectTypeOne") \
X(ZZObjectTypeTwo, , @"ZZObjectTypeTwo") \
X(ZZObjectTypeThree, , @"ZZObjectTypeThree")

+ (NSString*)nameForObjectType:(ZZObjectType)objectType {
#define X(a, b, c) @(a):c, 
    NSDictionary *dict = @{XXOBJECTTYPE_TABLE};
#undef X
    return dict[objectType];
}

それでおしまい。清潔で端正。@pixelに感謝!https://stackoverflow.com/users/21804/pixel


@AlexandreGがソリューションを提供します。誰かを狙うのは簡単です。このソリューションには、明らかな長所と短所があります。ソリューションで世界をより良いものにします。
ボイジャー

2

ここでいくつかのアプローチを組み合わせました。プリプロセッサとインデックス付きリストのアイデアが気に入っています。

余分な動的割り当てはなく、インライン化により、コンパイラーはルックアップを最適化できる場合があります。

typedef NS_ENUM(NSUInteger, FormatType) { FormatTypeJSON = 0, FormatTypeXML, FormatTypeAtom, FormatTypeRSS, FormatTypeCount };

NS_INLINE NSString *FormatTypeToString(FormatType t) {
  if (t >= FormatTypeCount)
    return nil;

#define FormatTypeMapping(value) [value] = @#value

  NSString *table[FormatTypeCount] = {FormatTypeMapping(FormatTypeJSON),
                                      FormatTypeMapping(FormatTypeXML),
                                      FormatTypeMapping(FormatTypeAtom),
                                      FormatTypeMapping(FormatTypeRSS)};

#undef FormatTypeMapping

  return table[t];
}

1

まず、FormatType.JSONに関しては、JSONはFormatTypeのメンバーではなく、型の可能な値です。FormatTypeは複合型でもなく、スカラーです。

次に、これを行う唯一の方法は、マッピングテーブルを作成することです。Objective-Cでこれを行うためのより一般的な方法は、「シンボル」を参照する一連の定数を作成することですNSString *FormatTypeJSON = @"JSON"


1

以下は、新しい列挙型を追加するために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);
    }
}

この技法は、誰かがそれについて読みたい場合に備えて、X-Macroと呼ばれます。これは、従来、FOR_EACH_GENDER()マクロは常にX()と呼ばれていたという事実から来ています。新しい意味で再定義する前に、#undef FOR_EACH_GENDERを実行することをお勧めします。
uliwitness 2017年

1

ここでのすべての答えは基本的に同じことを言い、通常の列挙型を作成し、カスタムゲッターを使用して文字列を切り替えます。

マクロを使用して、より速く、より短く、よりクリーンな、はるかに単純なソリューションを採用しています。


#define kNames_allNames ((NSArray <NSString *> *)@[@"Alice", @"Bob", @"Eve"])
#define kNames_alice ((NSString *)kNames_allNames[0])
#define kNames_bob ((NSString *)kNames_allNames[1])
#define kNames_eve ((NSString *)kNames_allNames[2])

次に、単に入力を開始できます kNam...を、オートコンプリートでのリストが表示されます。

さらに、すべての名前のロジックを一度に処理したい場合は、次のようにリテラル配列を順番に高速列挙するだけです。

for (NSString *kName in kNames_allNames) {}

最後に、マクロでのNSStringキャストにより、typedefと同様の動作が保証されます。


楽しい!


0

多くの答えはすべてかなり良いです。

いくつかのマクロを使用する汎用のObjective Cソリューションを使用している場合...

主な機能は、列挙型をNSString定数の静的配列へのインデックスとして使用することです。配列自体は関数にラップされ、Apple APIで広く使用されているNSStringFromXXX関数のスイートのようになります。

#import "NSStringFromEnum.h"ここで見つける必要があります http://pastebin.com/u83RR3Vk

[編集] #import "SW+Variadic.h"ここにも必要があります http://pastebin.com/UEqTzYLf

例1:文字列コンバータを使用して、新しい列挙型typedefを完全に定義します。

myfile.h


 #import "NSStringFromEnum.h"

 #define define_Dispatch_chain_cmd(enum)\
 enum(chain_done,=0)\
 enum(chain_entry)\
 enum(chain_bg)\
 enum(chain_mt)\
 enum(chain_alt)\
 enum(chain_for_c)\
 enum(chain_while)\
 enum(chain_continue_for)\
 enum(chain_continue_while)\
 enum(chain_break_for)\
 enum(chain_break_while)\
 enum(chain_previous)\
 enum(chain_if)\
 enum(chain_else)\


interface_NSString_Enum_DefinitionAndConverters(Dispatch_chain_cmd)

myfile.m:


 #import "myfile.h"

 implementation_NSString_Enum_Converters(Dispatch_chain_cmd)

使用する:

NSString *NSStringFromEnumDispatch_chain_cmd(enum Dispatch_chain_cmd value);

NSStringFromEnumDispatch_chain_cmd(chain_for_c) 戻り値 @"chain_for_c"

  enum Dispatch_chain_cmd enumDispatch_chain_cmdFromNSString(NSString *value);

enumDispatch_chain_cmdFromNSString(@"chain_previous") 戻り値 chain_previous

例2:既存の列挙型に変換ルーチンを提供することは、設定文字列の使用、および関数で使用されるタイプ名の名前の変更も示しています。

myfile.h


 #import "NSStringFromEnum.h"


 #define CAEdgeAntialiasingMask_SETTINGS_PARAMS CAEdgeAntialiasingMask,mask,EdgeMask,edgeMask

 interface_NSString_Enum_Converters(CAEdgeAntialiasingMask_SETTINGS_PARAMS)

myfile.m:


 // we can put this in the .m file as we are not defining a typedef, just the strings.
 #define define_CAEdgeAntialiasingMask(enum)\
 enum(kCALayerLeftEdge)\
 enum(kCALayerRightEdge)\
 enum(kCALayerBottomEdge)\
 enum(kCALayerTopEdge)



 implementation_NSString_Enum_Converters(CAEdgeAntialiasingMask_SETTINGS_PARAMS)

0

ここが機能しています-> 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;
}

重複した回答は許可されていないため、ここに完全なソリューションがあります github.com/ndpiparava/ObjcEnumString
Nitin

-2

必要に応じて、コンパイラディレクティブを使用して、探している動作をシミュレートすることもできます。

 #define JSON @"JSON"
 #define XML @"XML"
 #define Atom @"Atom"
 #define RSS @"RSS"

通常のコンパイラの欠点を覚えておいてください(タイプセーフではなく、直接コピーして貼り付けるとソースファイルが大きくなります)。


8
これでうまくいくとは思いません。どこでも#defineあなたは(つまり、実際の列挙型の値を使用することはできません、表示されているJSONに置き換えられてしまいます@"JSON"プリプロセッサでとに割り当てるとき、コンパイラエラーになりますFormatType
バリー覆うWark
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.