Ubah objektif-c typedef ke string yang setara


141

Dengan asumsi bahwa saya memiliki typedef yang dinyatakan dalam file .h saya seperti:

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

Saya ingin membangun fungsi yang mengubah nilai numerik dari typedef menjadi string. Misalnya, jika pesan [self toString:JSON]itu dikirim; itu akan mengembalikan 'JSON'.

Fungsi akan terlihat seperti ini:

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

Kebetulan, kalau saya coba sintaks ini

[self toString:FormatType.JSON];

untuk meneruskan nilai typedef ke metode, saya mendapatkan kesalahan. Apa yang saya lewatkan?


Lihat jawaban saya di stackoverflow.com/questions/6331762/enum-values-to-nsstring-ios untuk solusi yang lebih bersih untuk masalah ini.
BooTooMany

4
Mungkin kita harus memeluk bahasa Swift saat enum.
Itachi


Untuk solusi tanpa hanya menggunakan pengambil kustom untuk enum yang dikonversi ke string, lihat array makro string-cast: stackoverflow.com/a/53755377/2057171
Albert Renshaw

Jawaban:


135

Ini benar-benar pertanyaan C, tidak spesifik untuk Objective-C (yang merupakan superset dari bahasa C). Enum dalam C direpresentasikan sebagai bilangan bulat. Jadi, Anda perlu menulis fungsi yang mengembalikan string yang diberi nilai enum. Ada banyak cara untuk melakukan ini. Array string sehingga nilai enum dapat digunakan sebagai indeks ke dalam array atau struktur peta (misalnya an NSDictionary) yang memetakan nilai enum ke kerja string, tapi saya menemukan bahwa pendekatan ini tidak sejelas fungsi yang membuat konversi eksplisit (dan pendekatan array, meskipun Ccara klasik berbahaya jika nilai enum Anda tidak bertentangan dengan 0). Sesuatu seperti ini akan berhasil:

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

Pertanyaan terkait Anda tentang sintaks yang benar untuk nilai enum adalah bahwa Anda hanya menggunakan nilai (misalnya JSON), bukan FormatType.JSONsytax. FormatTypeadalah tipe dan nilai enum (mis JSON. XML, dll.) adalah nilai yang dapat Anda tetapkan untuk tipe itu.


127

Anda tidak dapat melakukannya dengan mudah. Dalam C dan Objective-C, enum adalah konstanta integer yang dimuliakan. Anda harus membuat sendiri daftar nama (atau dengan beberapa penyalahgunaan preprosesor). Sebagai contoh:

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

Bahaya dari pendekatan ini adalah bahwa jika Anda pernah mengubah enum, Anda harus ingat untuk mengubah susunan nama. Anda dapat memecahkan masalah ini dengan beberapa penyalahgunaan preprosesor, tetapi rumit dan jelek.

Perhatikan juga bahwa ini mengasumsikan Anda memiliki konstanta enum yang valid. Jika Anda memiliki nilai integer dari sumber yang tidak terpercaya, Anda juga perlu melakukan pengecekan bahwa konstanta Anda valid, misalnya dengan memasukkan nilai "max masa lalu" dalam enum Anda, atau dengan memeriksa apakah itu kurang dari panjang array sizeof(FormatType_toString) / sizeof(FormatType_toString[0]),.


37
Anda dapat menginisialisasi array dengan indeks eksplisit, misalnya string[] = { [XML] = "XML" }untuk memastikan string cocok dengan enum dengan benar
Christoph

@Christoph: Ya, itu fitur C99 yang disebut inisialisasi yang ditunjuk . Itu bagus untuk digunakan di Objective-C (yang didasarkan dari C99), tetapi untuk kode C89 umum, Anda tidak dapat menggunakannya.
Adam Rosenfield

Apakah ada cara untuk pergi ke arah lain? Misalnya, dapatkan enum kembali diberikan string?
Jameo

1
@Jameo: Ya, tapi tidak sesederhana melakukan pencarian array. Anda harus melakukan iterasi melalui FormatType_toString[]array dan memanggil -isEqualToString:setiap elemen untuk menemukan kecocokan, atau menggunakan tipe data pemetaan seperti NSDictionaryuntuk mempertahankan peta pencarian terbalik.
Adam Rosenfield

1
Trik Max O bagus untuk lupa menambahkan entri dalam FormatType_toStringarray.
AechoLiu

50

Solusi saya:

edit: Saya telah menambahkan solusi yang lebih baik di akhir, menggunakan Modern Obj-C

1.
Masukkan nama sebagai kunci dalam array.
Pastikan indeks adalah enum yang sesuai, dan dalam urutan yang benar (kecuali pengecualian).
note: names adalah properti yang disintesis sebagai * _names *;

kode tidak diperiksa untuk kompilasi, tetapi saya menggunakan teknik yang sama di aplikasi saya.

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.
Menggunakan Modern Obj-C Anda, kami dapat menggunakan kamus untuk mengikat deskripsi ke kunci di enum.
Memesan tidak masalah .

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


Penggunaan (dalam metode instance kelas):

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



12
Perlu diketahui bahwa setiap kali Anda menelepon +[typeDisplayNames], Anda membuat kembali kamus. Ini bagus jika hanya dipanggil beberapa kali, tetapi jika dipanggil berkali-kali, ini akan menjadi sangat mahal. Solusi yang lebih baik mungkin membuat kamus menjadi singleton, jadi itu hanya dibuat sekali dan tetap di memori sebaliknya. Memori klasik vs. teka-teki CPU.
Joel Fischer

Atau ubah menjadi variabel statis, mis. static NSDictionary *dict = nil; if(!dict) dict = @{@(UserTypeParent): @"Parent"}; return dict;Komentar tidak akan membiarkan Anda memutuskan, maaf untuk itu.
natanavra

29

Menggabungkan jawaban @AdamRosenfield, komentar @Christoph dan trik lain untuk menangani enum C sederhana saya sarankan:

// 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]);

Dalam kasus terburuk - seperti jika Anda mengubah enum tetapi lupa untuk mengubah array nama - itu akan mengembalikan nol untuk kunci ini.


12

define typedef enum di header kelas:

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

tulis metode seperti ini di kelas:

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

memiliki string di dalam file Localizable.strings :

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

11

Saya akan menggunakan token # string kompiler (bersama dengan makro untuk membuatnya lebih kompak):

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

Ini bekerja sangat baik di C99 - Saya baru di C, dan saya menemukan ini sebagai cara terbersih untuk menyelesaikan pertanyaan yang diajukan. Saya juga menambahkan secara default dalam implementasi saya untuk item yang mungkin belum ditentukan. Metode yang sangat bersih. Terima kasih atas hasilnya. Penggunaan Makro yang sangat licik.
TravisWhidden

8

Saya suka #definecara melakukan ini:

// Letakkan ini di file .h Anda, di luar blok @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];
}

sumber (sumber tidak lagi tersedia)


@ Daij-Djan bagaimana nilkalau kembali kalau array.count <= enumValue?
anneblue

@anneblue yang akan menangkap kesalahan .. itu akan tetap rapuh karena jika Anda menambahkan nilai enum ATAU nilai integer dari perubahan nilai enum ini salah. Jawaban yang diterima akan baik
Daij-Djan

@codercat :( maaf - tidak yakin apa yang terjadi pada situs web itu. Tidak juga di Saat Mesin Kembali ...
lindon fox

Saya punya pertanyaan kecil tentang jawaban di atas. Cara mengonversi elemen string ke kImageType. Saya perlu memanggil metode imageTypeEnumToString dengan melewatkan string. Bisakah Anda membantu saya untuk masalah saya.
Ganesh

1
Saya paling suka jawaban ini, karena Anda memiliki definisi string tepat di sebelah enum. Kesempatan terkecil dari kehilangan nilai. Dan @Ganesh, untuk mengkonversi dari nilai mentah, dapat melakukan ini: return (kImageType) [imageTypeArray indexOfObject: rawValue];
Harris

8

Saya membuat semacam campuran dari semua solusi yang ditemukan di halaman ini untuk membuat milik saya, itu semacam ekstensi enum berorientasi objek atau sesuatu.

Bahkan jika Anda membutuhkan lebih dari sekadar konstanta (yaitu bilangan bulat), Anda mungkin memerlukan objek model (Kita semua berbicara tentang MVC, bukan?)

Cukup tanyakan pada diri Anda pertanyaan sebelum menggunakan ini, apakah saya benar, bukankah Anda, pada kenyataannya, membutuhkan objek model nyata, diinisialisasi dari layanan web, sebuah plist, database SQLite atau CoreData?

Pokoknya inilah kode (MPI adalah untuk "Inisial Proyek Saya", tampaknya semua orang menggunakan ini atau nama mereka):

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

Dan 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

terlihat bagus, tetapi Anda mengalokasikan dan mengembalikan kamus penuh ketika Anda hanya membutuhkan salah satu dari nilainya. Efisiensi VS kode Cantik? tergantung pada apa yang Anda inginkan dan Anda akan baik-baik saja dengan ini jika Anda tidak menggunakannya sebanyak itu pada kode Anda seperti dalam satu lingkaran besar. Tetapi ini mungkin akan berguna dengan enums "dinamis" atau non-hard-code yang berasal dari server misalnya
user2387149

5

Solusi lain:

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

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

Dalam metode Anda, Anda dapat menggunakan:

NSString *operationCheck = AMZCartServiceOperationValue(operation);

4

Jawaban @ yar1vn yang ditingkatkan dengan menjatuhkan ketergantungan string:

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

Dengan demikian ketika Anda akan mengubah nama entri enum string yang sesuai akan diubah. Berguna jika Anda tidak akan menampilkan string ini kepada pengguna.


Bisakah Anda menjelaskan "- define VariableName (arg) (@" "# arg) --- dan mungkin memberikan solusi yang lebih baik?
xySVerma

Dengan #defines, ketika Anda menggunakan # untuk substitusi, argumen secara otomatis dibungkus dengan tanda kutip ganda. Dalam C, ketika dua string muncul di samping satu sama lain dalam kode seperti "foo""bar", itu menghasilkan string "foobar"ketika dikompilasi. Jadi, #define VariableName(arg) (@""#arg)akan berkembang VariableName(MyEnum)menjadi (@"""MyEnum"). Itu akan menghasilkan string @"MyEnum".
Chris Douglass

3

Diberikan definisi enum seperti:

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

Kita bisa mendefinisikan makro untuk mengonversi nilai enum ke string yang sesuai, seperti yang ditunjukkan di bawah ini.

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

The switchpernyataan yang digunakan di blok adalah untuk memeriksa jenis, dan juga untuk mendapatkan dukungan auto-lengkap dalam Xcode.

masukkan deskripsi gambar di sini masukkan deskripsi gambar di sini


2

Saya memiliki tipe enumerasi besar yang ingin saya ubah menjadi NSDictionarypencarian. Saya akhirnya menggunakan seddari terminal OSX sebagai:

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

yang dapat dibaca sebagai: 'tangkap kata pertama pada baris dan hasilkan @ (kata): @ "kata",'

Regex ini mengonversi enum dalam file header bernama 'ObservationType.h' yang berisi:

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

menjadi sesuatu seperti:

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

yang kemudian dapat dibungkus dengan metode menggunakan sintaks objektif-c modern @{ }(seperti yang dijelaskan oleh @ yar1vn di atas) untuk membuat NSDictionarypencarian:

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

The dispatch_onceboiler-piring hanya untuk memastikan bahwa variabel statis dijalankan dengan cara benang-aman.

Catatan: Saya menemukan ekspresi sed regex di OSX aneh - ketika saya mencoba menggunakan +untuk mencocokkan 'satu atau lebih' itu tidak berfungsi dan harus menggunakan {1,}sebagai pengganti


2

Saya menggunakan variasi pada jawaban Barry Walk, yang berurutan:

  1. Mengizinkan kompiler memeriksa klausa kasus yang hilang (tidak bisa jika Anda memiliki klausa default).
  2. Menggunakan nama khas Objective-C (bukan nama seperti Java).
  3. Meningkatkan pengecualian khusus.
  4. Lebih pendek.

MISALNYA:

- (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 menambahkan jawaban paling cemerlang di sini: https://stackoverflow.com/a/24255387/1364257 Tolong, upvote dia!

Dia menggunakan makro X yang rapi dari tahun 1960-an. (Saya telah sedikit mengubah kodenya untuk ObjC modern)

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

Itu dia. Bersih dan rapi. Terima kasih kepada @pixel! https://stackoverflow.com/users/21804/pixel


@AlexandreG memberikan solusi Anda, teman. Sangat mudah untuk memancing pada seseorang. Solusi ini memiliki kelebihan dan kekurangannya masing-masing. Jadikan dunia lebih baik dengan solusi Anda.
voiger

2

Saya menggabungkan beberapa pendekatan di sini. Saya suka ide preprocessor dan daftar yang diindeks.

Tidak ada alokasi dinamis tambahan, dan karena penyusun kompiler mungkin dapat mengoptimalkan pencarian.

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

Pertama-tama, berkenaan dengan FormatType.JSON: JSON bukan anggota dari FormatType, itu adalah nilai yang mungkin dari tipe tersebut. FormatType bahkan bukan tipe komposit - itu skalar.

Kedua, satu-satunya cara untuk melakukan ini adalah membuat tabel pemetaan. Cara yang lebih umum untuk melakukan ini di Objective-C adalah dengan membuat serangkaian konstanta yang mengacu pada "simbol" Anda, jadi Anda harus NSString *FormatTypeJSON = @"JSON"dan seterusnya.


1

berikut ini memberikan solusi sehingga untuk menambahkan enum baru hanya memerlukan satu baris edit, pekerjaan yang mirip dengan menambahkan satu baris dalam daftar enum {}.

//------------------------------------------------------------------------------
// 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);
    }
}

Teknik ini disebut X-Makro, kalau-kalau ada yang ingin membacanya. Itu berasal dari fakta bahwa, secara tradisional, makro FOR_EACH_GENDER () selalu disebut X (). Satu hal yang mungkin ingin Anda lakukan adalah #undef FOR_EACH_GENDER sebelum Anda mendefinisikannya kembali dengan makna baru.
uliwitness

1

Setiap jawaban di sini pada dasarnya mengatakan hal yang sama, membuat enum reguler dan kemudian menggunakan pengambil kustom untuk beralih di antara string.

Saya menggunakan solusi yang jauh lebih sederhana yang lebih cepat, lebih pendek, dan lebih bersih — menggunakan Macro!


#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])

Kemudian Anda bisa mulai mengetik kNam... dan pengisian otomatis akan menampilkan daftar yang Anda inginkan!

Selain itu, jika Anda ingin menangani logika untuk semua nama sekaligus, Anda dapat dengan cepat mencacah array literal secara berurutan, sebagai berikut:

for (NSString *kName in kNames_allNames) {}

Terakhir, casting NSString di makro memastikan perilaku yang mirip dengan typedef!


Nikmati!


0

Banyak jawaban semua cukup bagus.

Jika Anda mencari generik, solusi Objective C yang menggunakan beberapa makro ...

Fitur utamanya adalah ia menggunakan enum sebagai indeks ke dalam array statis konstanta NSString. array itu sendiri dibungkus menjadi suatu fungsi untuk membuatnya lebih seperti rangkaian fungsi NSStringFromXXX yang lazim di Apple API.

Anda perlu #import "NSStringFromEnum.h"ditemukan di sini http://pastebin.com/u83RR3Vk

[EDIT] juga perlu #import "SW+Variadic.h"ditemukan di sini http://pastebin.com/UEqTzYLf

Contoh 1: mendefinisikan sepenuhnya enum typedef BARU, dengan konverter string.

di 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)

di myfile.m:


 #import "myfile.h"

 implementation_NSString_Enum_Converters(Dispatch_chain_cmd)

menggunakan :

NSString *NSStringFromEnumDispatch_chain_cmd(enum Dispatch_chain_cmd value);

NSStringFromEnumDispatch_chain_cmd(chain_for_c) kembali @"chain_for_c"

  enum Dispatch_chain_cmd enumDispatch_chain_cmdFromNSString(NSString *value);

enumDispatch_chain_cmdFromNSString(@"chain_previous") kembali chain_previous

Contoh 2: menyediakan rutinitas konversi untuk enum yang ada juga menunjukkan menggunakan string pengaturan, dan mengganti nama nama pengguna yang digunakan dalam fungsi.

di myfile.h


 #import "NSStringFromEnum.h"


 #define CAEdgeAntialiasingMask_SETTINGS_PARAMS CAEdgeAntialiasingMask,mask,EdgeMask,edgeMask

 interface_NSString_Enum_Converters(CAEdgeAntialiasingMask_SETTINGS_PARAMS)

di 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

Ini berfungsi -> 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;
}

karena jawaban duplikat tidak diizinkan, berikut adalah solusi lengkap github.com/ndpiparava/ObjcEnumString
Nitin

-2

Bergantung pada kebutuhan Anda, Anda dapat menggunakan arahan kompiler sebagai alternatif untuk mensimulasikan perilaku yang Anda cari.

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

Ingat saja kekurangan kompiler yang biasa, (bukan tipe aman, langsung salin-tempel membuat file sumber lebih besar)


8
Saya tidak berpikir ini akan berhasil; di mana pun #defineterlihat, Anda tidak akan dapat menggunakan nilai enum yang sebenarnya (yaitu JSONakan diganti dengan @"JSON"oleh preprocessor dan akan menghasilkan kesalahan kompiler ketika menetapkan ke FormatType.
Barry Wark
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.