web-dev-qa-db-fra.com

enum Values ​​to NSString (iOS)

J'ai un enum tenant plusieurs valeurs:

enum {valeur1, valeur2, valeur3} maValeur;

À un certain moment de mon application, je souhaite vérifier quelle valeur de l'énum est maintenant active. J'utilise NSLog mais je ne vois pas trop comment afficher la valeur actuelle de l'énum (valeur1/valu2/valu3/etc ...) en tant que NSString pour le NSLog.

N'importe qui?

64
Ohad Regev

Ceci est répondu ici: quelques suggestions sur la mise en œuvre

La ligne du bas est Objective-C utilise un ancien et habituel Cenum, qui est simplement un ensemble glorifié d’entiers.

Étant donné un enum comme ceci:

typedef enum { a, b, c } FirstThreeAlpha;

Votre méthode ressemblerait à ceci:

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

Je n’ai pas aimé mettre l’enum sur le tas, sans fournir une fonction de tas pour la traduction. Voici ce que je suis venu avec:

typedef enum {value1, value2, value3} myValue;
#define myValueString(enum) [@[@"value1",@"value2",@"value3"] objectAtIndex:enum]

Ceci maintient les déclarations enum et string proches l'une de l'autre pour une mise à jour facile en cas de besoin.

Maintenant, n'importe où dans le code, vous pouvez utiliser l'enum/macro comme ceci:

myValue aVal = value2;
NSLog(@"The enum value is '%@'.", myValueString(aVal));

outputs: The enum value is 'value2'.

Pour garantir les index d'élément, vous pouvez toujours déclarer explicitement les valeurs de début (ou toutes) enum.

enum {value1=0, value2=1, value3=2};
85
Mark Longmire

Je vais vous présenter comment je l'utilise et cela a l'air mieux que la réponse précédente (je pense)

Je voudrais illustrer avec UIImageOrientation pour faciliter la compréhension.

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;

créer une méthode comme:

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

Tout ce que tu dois faire est :

  1. nommez votre fonction.

  2. copier le contenu de enum et coller celui entre NSArray * arr = @ [ et ]; return (NSString *) [arr objectAtIndex: input];

  3. mettre des @, "et des virgules

  4. PROFIT!!!!

34
Han-Jong Ko

Ceci sera validé par le compilateur, afin que vous ne mélangiez pas les index par inadvertance.

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]
29
Geri

J'ai trouvé ceci site web (d'où est tiré l'exemple ci-dessous) qui fournit une solution élégante à ce problème. La publication originale provient cependant de ceci réponse StackOverflow .

// 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;
}
13
ajmccall

Dans certains cas, lorsque vous devez convertir enum -> NSString et NSString -> enum, il peut être plus simple d’utiliser un typedef et #define (ou const NSStrings) au lieu d’enum:

typedef NSString *        ImageType;
#define ImageTypeJpg      @"JPG"
#define ImageTypePng      @"PNG"
#define ImageTypeGif      @"GIF"

et ensuite simplement opérer avec des chaînes "nommées" comme avec n'importe quel autre NSString:

@interface MyData : NSObject
@property (copy, nonatomic) ImageType imageType;
@end

@implementation MyData
- (void)doSomething {
    //...
    self.imageType = ImageTypePng;
    //...
    if ([self.imageType isEqualToString:ImageTypeJpg]) {
        //...
    }
}
@end
6
Leszek Szary

Si je peux offrir une autre solution qui présente l’avantage supplémentaire de la vérification de type, des avertissements si vous manquez une valeur enum dans votre conversion, votre lisibilité et votre brièveté.

Pour votre exemple donné: typedef enum { value1, value2, value3 } myValue; tu peux le faire:

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

En note de côté. Il est préférable de déclarer vos enums comme suit:

typedef NS_ENUM(NSInteger, MyValue) {
    Value1 = 0,
    Value2,
    Value3
}

Avec cela, vous obtenez une sécurité de type (NSInteger dans ce cas), vous définissez le décalage d’enum attendu (= 0).

6
JVillella

La solution ci-dessous utilise l'opérateur de chaîne du préprocesseur, ce qui permet une solution plus élégante. Il vous permet de définir les termes enum en un seul endroit pour une plus grande résistance aux fautes de frappe.

Commencez par définir votre enum de la manière suivante.

#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

Maintenant, utilisez-le de la manière suivante:

// Usage
MyFooEnum t = ENUM_ONE;
NSLog(@"Enum test - t is: %@", enumAsString[t]);

t = ENUM_TWO;
NSLog(@"Enum test - t is now: %@", enumAsString[t]);

qui produit:

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

La réponse de @ pixel m'a orienté dans la bonne direction.

4
BooTooMany

Vous trouverez ci-dessous un exemple d’Enum Struct compatible avec Objective-C si vous devez utiliser Swift Code dans les projets hérités écrits en Objective-C.

Exemple:

contentType.filename. toString ()

retourne "nom de fichier"


contentType.filename. rawValue

retourne la valeur Int, 1 (puisque c'est le deuxième élément de struct)

@objc enum contentType:Int {

    //date when content was created [RFC2183]
    case creationDate

    //name to be used when creating file    [RFC2183]
    case filename

    //whether or not processing is required [RFC3204]
    case handling

    //date when content was last modified   [RFC2183]
    case modificationDate

    //original field name in form   [RFC7578]
    case name

    //Internet media type (and parameters) of the preview output desired from a processor by the author of the MIME content [RFC-ietf-appsawg-text-markdown-12]
    case previewType

    //date when content was last read   [RFC2183]
    case readDate

    //approximate size of content in octets [RFC2183]
    case size

    //type or use of audio content  [RFC2421]
    case voice

    func toString() -> String {
        switch self {
        case .creationDate:
            return "creation-date"
        case .filename:
            return "filename"
        case .handling:
            return "handling"
        case .modificationDate:
            return "modification-date"
        case .name:
            return "name"
        case .previewType:
            return "preview-type"
        case .readDate:
                return "read-date"
        case .size:
            return "size"
        case .voice:
            return "voice"
        }
    }//eom
}//eo-enum
2
LuAndre

C'est une vieille question, mais si vous avez une énumération non contiguë, utilisez un littéral de dictionnaire au lieu d'un tableau:

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 ) ] \
)
2
Bob Provencher

Vous pouvez utiliser des macros X - elles sont parfaites pour cela.

Avantages 1. La relation entre la valeur enum réelle et la valeur de chaîne se trouve au même endroit. 2. vous pouvez utiliser les instructions switch habituelles plus tard dans votre code.

détriment 1. Le code d'installation initial est un peu obtus et utilise des macros amusantes.

Le code

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

#define XXOBJECTTYPE_TABLE \
X(ZZObjectTypeZero, = 0, "ZZObjectTypeZero") \
X(ZZObjectTypeOne, = 1, "ZZObjectTypeOne") \
X(ZZObjectTypeTwo, = 2, "ZZObjectTypeTwo") \
X(ZZObjectTypeThree, = 3, "ZZObjectTypeThree") \

+ (NSString*)nameForObjectType:(ZZObjectType)objectType {
#define X(a, b, c) @c, [NSNumber numberWithInteger:a],
    NSDictionary *returnValue = [NSDictionary dictionaryWithObjectsAndKeys:ZZOBJECTTYPE_TABLE nil];
#undef X
    return [returnValue objectForKey:[NSNumber numberWithInteger:objectType]];
}

+ (ZZObjectType)objectTypeForName:(NSString *)objectTypeString {
#define X(a, b, c) [NSNumber numberWithInteger:a], @c,
    NSDictionary *dictionary = [NSDictionary dictionaryWithObjectsAndKeys:ZZOBJECTSOURCE_TABLE nil];
#undef X
    NSUInteger value = [(NSNumber *)[dictionary objectForKey:objectTypeString] intValue];
    return (ZZObjectType)value;
}

Maintenant vous pouvez faire:

NSString *someString = @"ZZObjectTypeTwo"
ZZObjectType objectType = [[XXObject objectTypeForName:someString] intValue];
switch (objectType) {
    case ZZObjectTypeZero:
        //
        break;
    case ZZObjectTypeOne:
        //
        break;
    case ZZObjectTypeTwo:
        //
        break;
}

Ce modèle existe depuis les années 1960 (sans blague!): http://en.wikipedia.org/wiki/X_Macro

2
pixel

Voici une solution plug-and-play que vous pouvez étendre avec un simple copier-coller de vos définitions EXISTANTES.

J'espère que vous trouverez tous cela utile, comme j'ai trouvé utile de nombreuses autres solutions 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;
}

Voici les exemples de déclarations:

typedef enum _type1 {
ExampleNonExplicitTypeNEItemName1, 
ExampleNonExplicitTypeNEItemName2, 
ExampleNonExplicitTypeNEItemName3
} ExampleNonExplicitType;

typedef enum _type2 {
ExampleExplicitAssignsTypeEAItemName1 = 1, 
ExampleExplicitAssignsTypeEAItemName2 = 2, 
ExampleExplicitAssignsTypeEAItemName3 = 4
} ExampleExplicitAssignsType;

Voici un exemple d'appel:

NSLog(@"EXAMPLE:  type1:%@  type2:%@ ", [self enumItemNameForPrefix:@"ExampleNonExplicitType" item:ExampleNonExplicitTypeNEItemName2], [self enumItemNameForPrefix:@"ExampleExplicitAssignsType" item:ExampleExplicitAssignsTypeEAItemName3]);

Prendre plaisir! ;-)

2
eGanges

Supposons que l'exigence consiste à énumérer une liste de langues.

Ajouter ceci au fichier .h

typedef NS_ENUM(NSInteger, AvailableLanguage) {
  ENGLISH,
  GERMAN,
  CHINENSE
};

Maintenant, dans le fichier .m, créez simplement un tableau comme,

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

C'est ça. Vous pouvez maintenant utiliser enum avec easy et obtenir une chaîne pour les énumérations utilisant array. Par exemple,

- (void) setPreferredLanguage:(AvailableLanguage)language {
  // this will get the NSString* for the language.
  self.preferredLanguage = AvailableLanguageToString[language];
}

Ainsi, ce modèle dépend de la convention de dénomination acceptée de NS_ENUM et du tableau ToString associé. Essayez de suivre cette convention jusqu'au bout et cela deviendra naturel.

1
Market Queue

Ceci est similaire à la macro "X" publiée par pixel. merci pour le lien vers http://en.wikipedia.org/wiki/X_Macro

Le code généré dans les macros peut être difficile et difficile à déboguer. Au lieu de cela, générez une table utilisée par le code "normal". Je trouve que beaucoup de gens s'opposent à ce que les macros génèrent du code, ce qui explique peut-être pourquoi la technique des "macros X" présentée dans le wiki n'est pas largement adoptée.

En générant une table, vous n’avez toujours besoin que de modifier un emplacement pour étendre la liste, et comme vous ne pouvez pas "parcourir" une table dans le débogueur, cela élimine l’objection de beaucoup de personnes concernant le multi-lignes de code enfoui dans des macros.

//------------------------------------------------------------------------------
// enum to string example
#define FOR_EACH_GENDER(tbd) \
        tbd(GENDER_MALE) \
        tbd(GENDER_FEMALE) \
        tbd(GENDER_INTERSEX) \

#define ONE_GENDER_ENUM(name) name,
enum
{
    FOR_EACH_GENDER(ONE_GENDER_ENUM)
    MAX_GENDER
};

#define ONE_GENDER(name) #name,
static const char *enumGENDER_TO_STRING[] = 
{
    FOR_EACH_GENDER(ONE_GENDER)
};

// access string name with enumGENDER_TO_STRING[value]
// or, to be safe converting from a untrustworthy caller
static const char *enumGenderToString(unsigned int value)
{
    if (value < MAX_GENDER)
    {
        return enumGENDER_TO_STRING[value];
    }
    return NULL;
}

static void printAllGenders(void)
{
    for (int ii = 0;  ii < MAX_GENDER;  ii++)
    {
        printf("%d) gender %s\n", ii, enumGENDER_TO_STRING[ii]);
    }
}

//------------------------------------------------------------------------------
// you can assign an arbitrary value and/or information to each enum,
#define FOR_EACH_PERSON(tbd) \
        tbd(2, PERSON_FRED,     "Fred",     "Weasley", GENDER_MALE,   12) \
        tbd(4, PERSON_GEORGE,   "George",   "Weasley", GENDER_MALE,   12) \
        tbd(6, PERSON_HARRY,    "Harry",    "Potter",  GENDER_MALE,   10) \
        tbd(8, PERSON_HERMIONE, "Hermione", "Granger", GENDER_FEMALE, 10) \

#define ONE_PERSON_ENUM(value, ename, first, last, gender, age) ename = value,
enum
{
    FOR_EACH_PERSON(ONE_PERSON_ENUM)
};

typedef struct PersonInfoRec
{
    int value;
    const char *ename;
    const char *first;
    const char *last;
    int gender;
    int age;
} PersonInfo;

#define ONE_PERSON_INFO(value, ename, first, last, gender, age) \
                     { ename, #ename, first, last, gender, age },
static const PersonInfo personInfo[] = 
{
    FOR_EACH_PERSON(ONE_PERSON_INFO)
    { 0, NULL, NULL, NULL, 0, 0 }
};
// note: if the enum values are not sequential, you need another way to lookup
// the information besides personInfo[ENUM_NAME]

static void printAllPersons(void)
{
    for (int ii = 0;  ;  ii++)
    {
        const PersonInfo *pPI = &personInfo[ii];
        if (!pPI->ename)
        {
            break;
        }
        printf("%d) enum %-15s  %8s %-8s %13s %2d\n",
            pPI->value, pPI->ename, pPI->first, pPI->last,
            enumGenderToString(pPI->gender), pPI->age);
    }
}
0
fredwork

Voici le code de travailhttps://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;
}
0
Nit
  1. une macro:

    #define stringWithLiteral(literal) @#literal
    
  2. un enum:

    typedef NS_ENUM(NSInteger, EnumType) {
        EnumType0,
        EnumType1,
        EnumType2
    };
    
  3. un tableau:

    static NSString * const EnumTypeNames[] = {
        stringWithLiteral(EnumType0),
        stringWithLiteral(EnumType1),
        stringWithLiteral(EnumType2)
    };
    
  4. en utilisant:

    EnumType enumType = ...;
    NSString *enumName = EnumTypeNames[enumType];
    

==== EDIT ====

Copiez le code suivant dans votre projet et exécutez-le.

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