Konvertieren Sie object-c typedef in sein String-Äquivalent

Lesezeit: 7 Minuten

craigs Benutzeravatar
Craig

Angenommen, ich habe eine Typedef in meiner .h-Datei als solche deklariert:

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

Ich möchte eine Funktion bauen, die den numerischen Wert des Typedef in einen String umwandelt. Wenn zum Beispiel die Nachricht [self toString:JSON] wurde gesendet; es würde ‘JSON’ zurückgeben.

Die Funktion würde in etwa so aussehen:

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

Übrigens, wenn ich diese Syntax versuche

[self toString:FormatType.JSON];

Um den typedef-Wert an die Methode zu übergeben, erhalte ich eine Fehlermeldung. Was vermisse ich?

  • Siehe meine Antwort unter stackoverflow.com/questions/6331762/enum-values-to-nsstring-ios für eine sauberere Lösung des Problems.

    – BooTooMany

    22. Oktober 2014 um 20:52 Uhr

  • Vielleicht sollten wir eine Umarmung geben Schnell Sprache auf Aufzählung.

    – Itachi

    26. August 2016 um 9:33 Uhr

  • @craig: hier ist die Lösung github.com/ndpiparava/ObjcEnumString

    – Nitin

    5. März 2017 um 17:07 Uhr


  • Für eine Lösung, ohne einfach einen benutzerdefinierten Getter für Enum zu verwenden, der in einen String konvertiert, sehen Sie sich das String-Cast-Makro-Array an: stackoverflow.com/a/53755377/2057171

    – Albert Renshaw

    13. Dezember 2018 um 5:23 Uhr

Benutzeravatar von Barry Wark
Barry Wark

Dies ist wirklich eine C-Frage, nicht spezifisch für Objective-C (das eine Obermenge der C-Sprache ist). Aufzählungen in C werden als ganze Zahlen dargestellt. Sie müssen also eine Funktion schreiben, die einen String mit einem Enum-Wert zurückgibt. Es gibt viele Möglichkeiten, dies zu tun. Ein Array von Strings, sodass der Enum-Wert als Index in das Array oder eine Map-Struktur (z. B. eine NSDictionary), die einen Enum-Wert einem String zuordnet, funktionieren, aber ich finde, dass diese Ansätze nicht so klar sind wie eine Funktion, die die Konvertierung explizit macht (und der Array-Ansatz, obwohl der klassische C Weg ist gefährlich, wenn Ihre Enum-Werte nicht fortlaufend von 0 sind). So etwas würde funktionieren:

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

Ihre verwandte Frage zur korrekten Syntax für einen Aufzählungswert ist, dass Sie nur den Wert verwenden (z JSON), nicht der FormatType.JSON Syntax. FormatType ein Typ ist und die Aufzählungswerte (zB JSON, XMLusw.) sind Werte, die Sie diesem Typ zuweisen können.

Benutzeravatar von Adam Rosenfield
Adam Rosenfeld

Sie können es nicht einfach tun. In C und Objective-C sind Aufzählungen wirklich nur verherrlichte ganzzahlige Konstanten. Sie müssen selbst (oder mit etwas Vorprozessormissbrauch) eine Tabelle mit Namen erstellen. Zum Beispiel:

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

Die Gefahr bei diesem Ansatz besteht darin, dass Sie, wenn Sie jemals die Aufzählung ändern, daran denken müssen, das Array der Namen zu ändern. Sie können dieses Problem mit etwas Präprozessormissbrauch lösen, aber es ist knifflig und hässlich.

Beachten Sie auch, dass dies davon ausgeht, dass Sie eine gültige Aufzählungskonstante haben. Wenn Sie einen ganzzahligen Wert aus einer nicht vertrauenswürdigen Quelle haben, müssen Sie zusätzlich überprüfen, ob Ihre Konstante gültig ist, z. sizeof(FormatType_toString) / sizeof(FormatType_toString[0]).

  • Sie können Arrays mit expliziten Indizes initialisieren, z string[] = { [XML] = "XML" } um sicherzustellen, dass die Zeichenfolge richtig mit den Aufzählungen übereinstimmt

    – Christoph

    7. Juli 2009 um 23:39 Uhr

  • @Christoph: Ja, das ist ein C99-Feature namens ausgewiesene Initialisierer. Das ist gut für die Verwendung in Objective-C (das auf C99 basiert), aber für generischen C89-Code können Sie diese nicht verwenden.

    – Adam Rosenfield

    3. September 2013 um 17:55 Uhr

  • Gibt es eine Möglichkeit, in die andere Richtung zu gehen? Zum Beispiel die Aufzählung bei einer Zeichenfolge zurückerhalten?

    – Jameo

    17. Februar 2014 um 16:44 Uhr

  • @Jameo: Ja, aber es ist nicht ganz so einfach wie eine Array-Suche durchzuführen. Sie müssen entweder durch die iterieren FormatType_toString[] Array und Aufruf -isEqualToString: für jedes Element, um eine Übereinstimmung zu finden, oder verwenden Sie einen Mapping-Datentyp wie z NSDictionary um die inverse Nachschlagekarte beizubehalten.

    – Adam Rosenfield

    17. Februar 2014 um 16:55 Uhr

  • Der Trick von Max O ist gut, um zu vergessen, Einträge in der hinzuzufügen FormatType_toString Reihe.

    – AechoLiu

    15. Dezember 2015 um 2:47 Uhr

Benutzeravatar von Yariv Nissim
Jariv Nissim

Meine Lösung:

Bearbeiten: Ich habe am Ende noch eine bessere Lösung hinzugefügt, mit Modern Obj-C

1.
Geben Sie Namen als Schlüssel in ein Array ein.
Stellen Sie sicher, dass die Indizes die entsprechenden Aufzählungen sind, und in der richtigen reihenfolge (sonst Ausnahme).
Hinweis: Namen ist eine als *_names* synthetisierte Eigenschaft;

Code wurde nicht auf Kompilierung geprüft, aber ich habe die gleiche Technik in meiner App verwendet.

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.
Mit Modern Obj-C können Sie ein Wörterbuch verwenden, um Beschreibungen mit Schlüsseln in der Aufzählung zu verknüpfen.
Die Reihenfolge spielt keine Rolle.

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

Verwendung (in einer Klasseninstanzmethode):

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

  • Beachten Sie das bei jedem Anruf +[typeDisplayNames], erstellen Sie das Wörterbuch neu. Das ist in Ordnung, wenn es nur ein paar Mal aufgerufen wird, aber wenn es viele Male aufgerufen wird, wird es sehr teuer. Eine bessere Lösung könnte darin bestehen, das Wörterbuch zu einem Singleton zu machen, sodass es nur einmal erstellt wird und ansonsten im Speicher bleibt. Klassisches Speicher-vs.-CPU-Rätsel.

    – Joel Fischer

    11. April 2014 um 14:24 Uhr


  • Oder ändern Sie es in eine statische Variable, z static NSDictionary *dict = nil; if(!dict) dict = @{@(UserTypeParent): @"Parent"}; return dict; Kommentare lassen keinen Zeilenumbruch zu, tut mir leid.

    – Natanavra

    29. Juni 2017 um 14:44 Uhr


Ich schlage vor, die Antwort von @AdamRosenfield, den Kommentar von @Christoph und einen weiteren Trick zum Umgang mit einfachen C-Enumerationen zu kombinieren:

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

Im schlimmsten Fall – wie wenn Sie die Aufzählung ändern, aber vergessen, das Namens-Array zu ändern – wird für diesen Schlüssel null zurückgegeben.

typedef enum im Klassenheader definieren:

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

Schreiben Sie eine Methode wie diese in der Klasse:

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

habe die Saiten drin Lokalisierbare.strings Datei:

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

Benutzeravatar von Pete
Peter

Ich würde das # String-Token des Compilers verwenden (zusammen mit Makros, um alles kompakter zu machen):

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

Ich mag #define Vorgehensweise:

// Platzieren Sie dies in Ihrer .h-Datei außerhalb des @interface-Blocks

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

Quelle (Quelle nicht mehr verfügbar)

  • @Daij-Djan, was ist mit der Rückkehr nil wenn array.count <= enumValue?

    – anneblue

    14. März 2014 um 10:13 Uhr


  • @anneblue, das würde den Fehler abfangen. Es wäre immer noch zerbrechlich, denn wenn Sie einen Aufzählungswert hinzufügen ODER sich der ganzzahlige Wert eines Aufzählungswerts ändert, geht dies schief. Die akzeptierte Antwort wäre gut

    – Daij-Djan

    14. März 2014 um 12:18 Uhr

  • @codercat 🙁 Entschuldigung – ich bin mir nicht sicher, was mit dieser Website passiert ist. Nicht auf dem Weg zurück, wenn die Maschine auch …

    – Lindon Fuchs

    20. Mai 2014 um 7:06 Uhr

  • Ich habe eine kleine Frage zu obiger Antwort. So konvertieren Sie ein Zeichenfolgenelement in kImageType. Ich muss die imageTypeEnumToString-Methode aufrufen, indem ich die Zeichenfolge übergebe. Können Sie mir bitte bei meinem Problem helfen?

    – Ganesh

    6. Oktober 2014 um 12:27 Uhr

  • Diese Antwort gefällt mir am besten, weil Sie die Zeichenfolgendefinitionen direkt neben den Aufzählungen haben. Geringste Chance, einen Wert zu verpassen. Und @Ganesh könnte Folgendes tun, um den Rohwert zu konvertieren: return (kImageType)[imageTypeArray indexOfObject:rawValue];

    – Elia

    4. Januar 2015 um 7:38 Uhr


1424110cookie-checkKonvertieren Sie object-c typedef in sein String-Äquivalent

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy