Objektif-c typedef'i dize eşdeğerine dönüştürün


141

.H dosyamda olduğu gibi bir typedef var olduğunu varsayarsak:

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

Typedef sayısal değerini bir dizeye dönüştüren bir işlev oluşturmak istiyorum. Örneğin, mesaj [self toString:JSON]gönderildiyse; 'JSON' döndürecektir.

İşlev şöyle görünecektir:

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

Bu arada, bu sözdizimini denersem

[self toString:FormatType.JSON];

typedef değerini yönteme geçirmek için bir hata alıyorum. Neyi kaçırıyorum?


Soruna daha temiz bir çözüm için cevabımı stackoverflow.com/questions/6331762/enum-values-to-nsstring-ios adresinden görebilirsiniz .
BooTooMany

4
Belki enum'da Swift diline sarılmalıyız.
Itachi

@craig: İşte çözüm github.com/ndpiparava/ObjcEnumString
Nitin

Dize dönüştüren enum için özel bir alıcı kullanmadan bir çözüm için, dizi döküm makro dizisine göz
Albert Renshaw

Yanıtlar:


135

Bu gerçekten bir C sorusudur, Objective-C'ye özgü değildir (C dilinin bir üst kümesidir). C'deki numaralandırmalar tamsayı olarak temsil edilir. Bu nedenle, enum değeri verilen bir dize döndüren bir işlev yazmanız gerekir. Bunu yapmanın birçok yolu var. Enum değeri diziye bir dizin olarak veya NSDictionarybir dize çalışmasına bir enum değeri eşleyen bir harita yapısı (örneğin bir ) olarak kullanılabilecek dizeleri bir dizi , ancak bu yaklaşımların bir işlev kadar net olmadığını buluyorum klasik (her ne kadar klasik olsa da)C enum değerleriniz 0'dan koşullu değilse yol tehlikeli olsa da). Bunun gibi bir şey işe yarayacaktır:

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

Bir enum değeri için doğru sözdizimiyle ilgili sorunuz JSON, FormatType.JSONsytax değil, yalnızca değeri (örn. ) Kullanmanızdır. FormatTypebir türdür ve numaralandırma değerleri (ör JSON. XML, vb.) bu türe atayabileceğiniz değerlerdir.


127

Kolayca yapamazsın. C ve Objective-C'de sıralamalar gerçekten sadece yüceltilmiş tamsayı sabitleridir. Kendiniz bir ad tablosu (veya bazı önişlemci kötüye kullanımı ile) oluşturmanız gerekir. Örneğin:

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

Bu yaklaşımın tehlikesi, sıralamayı değiştirirseniz, ad dizisini değiştirmeyi hatırlamanız gerektiğidir. Bu sorunu önişlemci kötüye kullanımı ile çözebilirsiniz, ancak bu zor ve çirkin.

Ayrıca bunun geçerli bir numaralandırma sabitiniz olduğunu varsaydığını unutmayın. Güvenilmeyen bir kaynaktan bir tamsayı değeriniz varsa, ek olarak sabitinizin geçerli olup olmadığını, örneğin numaralandırmanıza "geçmiş maksimum" değerini ekleyerek veya dizi uzunluğundan az olup olmadığını denetleyerek yapmanız gerekir sizeof(FormatType_toString) / sizeof(FormatType_toString[0]).


37
dizileri açık dizinlerle başlatabilirsiniz; örneğin string[] = { [XML] = "XML" }, dizenin numaralandırmalarla düzgün şekilde eşleştiğinden emin olmak için
Christoph

@Christoph: Evet, belirlenmiş başlatıcılar adı verilen bir C99 özelliği . Objective-C'de (C99 tabanlı) kullanmak iyidir, ancak genel C89 kodu için bunları kullanamazsınız.
Adam Rosenfield

Diğer yöne gitmenin bir yolu var mı? Örneğin, enum bir dize verilsin mi?
Jameo

1
@Jameo: Evet, ancak dizi araması yapmak kadar basit değil. Bir eşleşme bulmak için FormatType_toString[]diziyi yinelemeniz ve -isEqualToString:her öğeyi çağırmanız veya NSDictionaryters arama haritasını korumak gibi bir eşleme veri türü kullanmanız gerekir .
Adam Rosenfield

1
Max O'nun püf noktası, FormatType_toStringdiziye giriş eklemeyi unutmak konusunda iyidir .
AechoLiu

50

Benim çözümüm:

edit: Modern Obj-C

1 kullanarak sonunda daha iyi bir çözüm ekledim.
İsimleri anahtar olarak bir diziye koyun.
Dizinlerin uygun numaralandırmalar ve doğru sırada olduğundan emin olun (aksi takdirde istisna).
not: isimler , * _names * olarak sentezlenen bir özelliktir;

kod derleme için kontrol edilmedi, ama benim app aynı tekniği kullandım.

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'yi kullanarak açıklamaları enumdaki tuşlara bağlamak için kullanabilirsiniz.
Sipariş önemli değil .

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


Kullanım (bir sınıf örneği yönteminde):

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



12
Her aradığınızda +[typeDisplayNames]sözlüğü yeniden oluşturduğunuzu unutmayın. Sadece birkaç kez çağrılırsa bu iyidir, ancak birçok kez çağrılırsa, bu çok pahalı olacaktır. Daha iyi bir çözüm, sözlüğü tek birton yapmak olabilir, bu yüzden sadece bir kez oluşturulur ve aksi takdirde bellekte kalır. Klasik bellek ve CPU bilmecesi.
Joel Fischer

Veya statik bir değişken olarak değiştirin, örneğin static NSDictionary *dict = nil; if(!dict) dict = @{@(UserTypeParent): @"Parent"}; return dict;Yorumlar bunun için satır kesmenize izin vermez, bunun için üzgünüm.
natanavra

29

@AdamRosenfield cevabı, @Christoph yorumu ve düz C numaralarını işlemek için başka bir numarayı birleştirerek öneririm:

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

En kötü durumda - numaralandırmayı değiştirirseniz, ancak ad dizisini değiştirmeyi unutursanız - bu anahtar için nil döndürür.


12

sınıf başlığında typedef enum tanımlayın:

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

sınıfta böyle bir yöntem yazın:

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

dizeleri Localizable.strings dosyasının içinde bulundurun :

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

11

Derleyicinin # dize belirtecini (makrolarla birlikte daha kompakt hale getirmek için) kullanırdım:

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

Bu C99'da harika çalıştı - C'de yeniyim ve bunu sorulan soruyu gerçekleştirmenin en temiz yolu olarak buldum. Ayrıca, tanımlanmamış öğeler için uygulamamda varsayılan olarak ekledim. Çok temiz bir yöntem. Sonuçlar için teşekkürler. Bir makronun çok kurnaz kullanımı.
TravisWhidden

8

Hoşuma gitti #define yapmanın yolunu :

// Bunu .inter dosyanıza @interface bloğunun dışına yerleştirin

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

kaynak (kaynak artık mevcut değil)


Daij-Djan @ yaklaşık dönen Ne nilolursa array.count <= enumValue?
anneblue

@anneblue bu hatayı yakalar .. kırılgan olacaktır çünkü bir enum değeri eklerseniz VEYA bir enum değerinin tamsayı değeri değişirse bu yanlış olur. Kabul edilen cevap iyi olurdu
Daij-Djan

@codercat :( özür dilerim - bu web sitesine ne olduğundan emin değilim. Geri
Dönüşte

Yukarıdaki cevap hakkında küçük bir sorum var. Dize öğesini kImageType'a dönüştürme. Dize geçirerek imageTypeEnumToString yöntemini çağırmak gerekir.Lütfen benim sorunum için bana yardımcı olabilir misiniz.
Ganesh

1
Bu cevabı en çok sevdim, çünkü numaralandırmaların hemen yanında dize tanımları var. En az bir değeri kaçırma şansı. Ve @Ganesh, ham değerden dönüştürmek için bunu yapabilirdi: return (kImageType) [imageTypeArray indexOfObject: rawValue];
Harris

8

Benimki oluşturmak için bu sayfada bulunan tüm çözümlerin bir karışımını yaptım, bir çeşit nesne odaklı numaralandırma uzantısı veya başka bir şey.

Aslında sabitlerden (yani tamsayılardan) fazlasına ihtiyacınız varsa, muhtemelen bir model nesnesine ihtiyacınız vardır (Hepimiz MVC hakkında konuşuyoruz, değil mi?)

Bunu kullanmadan önce kendinize sormanız yeterlidir, haklı mıyım, aslında, bir web servisinden, bir plistten, bir SQLite veritabanından veya CoreData'dan başlatılan gerçek bir model nesnesine ihtiyacınız yok mu?

Her neyse burada kod geliyor (MPI "Proje Baş Harflerim" içindir, herkes bunu veya adını kullanır, öyle görünüyor):

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

Ve 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

güzel görünüyor, ancak değerlerinden yalnızca birine ihtiyacınız olduğunda tam sözlükler tahsis ediyor ve iade ediyorsunuz. Verimlilik VS Güzel kod? Ne istediğinize bağlıdır ve büyük bir döngüde olduğu gibi kodunuzda bu kadar kullanmazsanız, bununla iyi olacaksınız. Ancak bu, örneğin bir sunucudan gelen "dinamik" veya sabit kodlu olmayan numaralandırmalar için yararlı olacaktır
user2387149 10:15

5

Başka bir çözüm:

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

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

Yönteminizde şunları kullanabilirsiniz:

NSString *operationCheck = AMZCartServiceOperationValue(operation);

4

Dize bağımlılığını bırakarak @ yar1vn yanıtı geliştirildi:

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

Böylece numaralandırma giriş adını değiştirdiğinizde karşılık gelen dize değişecektir. Bu dizeyi kullanıcıya göstermezseniz kullanışlıdır.


"- VariableName (arg) (@" "# arg) --- 'u açıklayabilir ve muhtemelen daha iyi bir çözüm verebilir misiniz?
xySVerma

#Defines ile, yerine koyma için # kullandığınızda, bağımsız değişken otomatik olarak çift tırnak içine alınır. C, iki dize gibi kod içinde yan yana göründüğünde "foo""bar", "foobar"derlendiğinde dize ile sonuçlanır . Yani, #define VariableName(arg) (@""#arg)genişleyecektir VariableName(MyEnum)olmak (@"""MyEnum"). Bu dize ile sonuçlanacaktır @"MyEnum".
Chris Douglass

3

Aşağıdaki gibi bir numaralandırma tanımı verildi:

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

Bir enum değerini aşağıda gösterildiği gibi karşılık gelen dizeye dönüştürmek için bir makro tanımlayabiliriz.

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

switchBloğunda kullanılan deyim tür denetleme için olduğunu ve aynı zamanda Xcode otomatik tamamlama destek almak için.

resim açıklamasını buraya girin resim açıklamasını buraya girin


2

Bir aramaya dönüştürmek istediğim büyük bir numaralandırılmış tipim vardı NSDictionary. Ben sedOSX terminali olarak kullanarak sona erdi :

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

şu şekilde okunabilir: 'satırdaki ilk kelimeyi yakalayın ve @ (word) çıktısını alın: @ "word",'

Bu normal ifade, aşağıdakileri içeren 'ObservationType.h' başlık dosyasındaki enum'u dönüştürür:

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

gibi bir şeye:

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

daha sonra @{ }bir NSDictionaryarama oluşturmak için modern obj -c sözdizimi (yukarıdaki @ yar1vn tarafından açıklandığı gibi) kullanılarak bir yönteme sarılabilir :

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

dispatch_onceKazan-plaka sadece statik değişken bir iş parçacığı güvenli bir şekilde başlatıldı emin olmak için bir.

Not: OSX'de sed regex ifadesini buldum - +'bir veya daha fazla' ile eşleşmeye çalıştığımda işe yaramadı ve {1,}yedek olarak kullanmaya başvurmak zorunda kaldım


2

Barry Walk'un cevabında, önem sırasına göre bir varyasyon kullanıyorum:

  1. Derleyicinin eksik büyük / küçük harf yanlarını denetlemesine izin verir (varsayılan yan tümceniz varsa bunu yapamaz).
  2. Objective-C tipik adı kullanır (Java benzeri bir ad yerine).
  3. Belirli bir istisna oluşturur.
  4. Daha kısadır.

ÖRNEĞİN:

- (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 en parlak yanıtı buraya ekledi: https://stackoverflow.com/a/24255387/1364257 Lütfen, onu oylayın!

1960'lı yıllardan itibaren düzgün X makrosunu kullanıyor. (Modern ObjC için kodunu biraz değiştirdim)

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

Bu kadar. Temiz ve düzenli. @Pixel sayesinde! https://stackoverflow.com/users/21804/pixel


@AlexandreG çözümünüzü sağlayın adamım. Birisine sazanlamak kolaydır. Bu çözümün hem belirgin artıları hem de belirgin eksileri vardır. Çözümünüzle dünyayı daha iyi hale getirin.
voiger

2

Burada birkaç yaklaşımı birleştirdim. Önişlemci ve dizinli liste fikrini seviyorum.

Ekstra dinamik ayırma yoktur ve satır içi ayar nedeniyle derleyici aramayı optimize edebilir.

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

Her şeyden önce, FormatType.JSON ile ilgili olarak: JSON, FormatType üyesi değil, türün olası bir değeridir. FormatType, bileşik bir tür bile değildir - bir skalerdir.

İkincisi, bunu yapmanın tek yolu bir eşleme tablosu oluşturmaktır. Objective-C'de bunu yapmanın en yaygın yolu "sembollerinize" atıfta bulunan bir dizi sabit oluşturmaktır NSString *FormatTypeJSON = @"JSON".


1

aşağıda, yeni bir numaralandırma eklemek için yalnızca bir satırlık düzenleme ve benzer bir çalışma, bir numaralandırma {} listesine tek bir satır eklemek için benzer bir çözüm sunulmaktadır.

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

Bu tekniğe X-Macro denir, birinin okumak istediği durumda. Bu, geleneksel olarak, FOR_EACH_GENDER () makrosunun her zaman sadece X () olarak adlandırılmasından kaynaklanmaktadır. Yapmak isteyebileceğiniz şeylerden biri, yeni bir anlamla yeniden tanımlamadan önce #undef FOR_EACH_GENDER.
uliwitness

1

Buradaki her cevap temel olarak aynı şeyi söyler, düzenli bir numaralandırma oluşturur ve ardından dizeler arasında geçiş yapmak için özel bir alıcı kullanır.

Makroları kullanarak daha hızlı, daha kısa ve daha temiz olan çok daha basit bir çözüm kullanıyorum!


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

Sonra yazmaya başlayabilirsiniz kNam...ve otomatik tamamlama istediğiniz listeleri gösterecektir!

Ayrıca, tüm adlar için bir kerede mantığı işlemek istiyorsanız, basit bir şekilde sıralı diziyi aşağıdaki gibi hızlı bir şekilde numaralandırabilirsiniz:

for (NSString *kName in kNames_allNames) {}

Son olarak, makrolardaki NSString dökümü, typedef!


Zevk almak!


0

Birçok cevap oldukça iyi.

Bazı makrolar kullanan genel, Objective C çözümü peşindeyseniz ...

En önemli özelliği, numaralandırmayı NSString sabitlerinin statik bir dizisine dizin olarak kullanmasıdır. dizinin kendisi, daha çok Apple API'lerinde yaygın olan NSStringFromXXX işlevleri paketi gibi bir işleve sarılır.

#import "NSStringFromEnum.h"burada bulman gerekecek http://pastebin.com/u83RR3Vk

[EDIT] ayrıca #import "SW+Variadic.h"burada bulunması gerekiyor http://pastebin.com/UEqTzYLf

Örnek 1: Dize dönüştürücülerle tamamen YENİ bir enum typedef tanımlayın.

myfile.h dosyasında


 #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 dosyasında:


 #import "myfile.h"

 implementation_NSString_Enum_Converters(Dispatch_chain_cmd)

kullanmak :

NSString *NSStringFromEnumDispatch_chain_cmd(enum Dispatch_chain_cmd value);

NSStringFromEnumDispatch_chain_cmd(chain_for_c) İadeler @"chain_for_c"

  enum Dispatch_chain_cmd enumDispatch_chain_cmdFromNSString(NSString *value);

enumDispatch_chain_cmdFromNSString(@"chain_previous") İadeler chain_previous

Örnek 2: Varolan bir numaralandırma için dönüşüm rutinleri sağlayın ayrıca bir ayarlar dizesi kullanmayı ve işlevlerde kullanılan yazım adının yeniden adlandırılmasını gösterir.

myfile.h dosyasında


 #import "NSStringFromEnum.h"


 #define CAEdgeAntialiasingMask_SETTINGS_PARAMS CAEdgeAntialiasingMask,mask,EdgeMask,edgeMask

 interface_NSString_Enum_Converters(CAEdgeAntialiasingMask_SETTINGS_PARAMS)

myfile.m dosyasında:


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

İşte çalışıyor -> 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;
}

yinelenen yanıtlamaya izin verilmediğinden, tam çözüm burada github.com/ndpiparava/ObjcEnumString
Nitin

-2

İhtiyaçlarınıza bağlı olarak, aradığınız davranışı simüle etmek için derleyici yönergelerini kullanabilirsiniz.

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

Her zamanki derleyici eksikliklerini hatırlayın, (güvenli değil, doğrudan kopyala yapıştır kaynak dosyasını büyütür)


8
Bunun işe yarayacağını sanmıyorum; her yerde #definegerçek enum değeri kullanmak mümkün olmayacaktır, görünür durumda (yani JSONdeğiştirilir alacak @"JSON"önişlemci tarafından ve bir karşı atarken bir derleyici hata ile sonuçlanır FormatType.
Barry Wark
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.