Chuyển đổi typedef mục tiêu thành chuỗi tương đương


141

Giả sử rằng tôi có một typedef được khai báo trong tệp .h của mình như sau:

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

Tôi muốn xây dựng một hàm chuyển đổi giá trị số của typedef thành một chuỗi. Ví dụ, nếu tin nhắn [self toString:JSON]được gửi đi; nó sẽ trả về 'JSON'.

Hàm này sẽ trông giống như thế này:

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

Ngẫu nhiên, nếu tôi thử cú pháp này

[self toString:FormatType.JSON];

để truyền giá trị typedef cho phương thức, tôi gặp lỗi. Tôi đang thiếu gì?


Xem câu trả lời của tôi tại stackoverflow.com/questions/6331762/enum-values-to-nsopes-ios để biết giải pháp sạch hơn cho vấn đề này.
BooTooMany

4
Có lẽ chúng ta nên ôm một ngôn ngữ Swift trên enum.
Itachi

@craig: đây là giải pháp github.com/ndpiparava/ObjcEnumString
Nitin

Để biết giải pháp mà không chỉ đơn giản là sử dụng một getter tùy chỉnh cho enum chuyển đổi thành chuỗi, hãy kiểm tra mảng macro đúc chuỗi: stackoverflow.com/a/53755377/2057171
Albert Renshaw

Câu trả lời:


135

Đây thực sự là một câu hỏi C, không dành riêng cho Objective-C (là một siêu ngôn ngữ của ngôn ngữ C). Enums trong C được biểu diễn dưới dạng số nguyên. Vì vậy, bạn cần phải viết một hàm trả về một chuỗi có giá trị enum. Có rất nhiều cách để làm điều này. Một mảng các chuỗi sao cho giá trị enum có thể được sử dụng làm chỉ mục vào mảng hoặc cấu trúc bản đồ (ví dụ NSDictionary:) ánh xạ giá trị enum vào chuỗi hoạt động, nhưng tôi thấy rằng các cách tiếp cận này không rõ ràng như một hàm làm cho chuyển đổi rõ ràng (và cách tiếp cận mảng, mặc dù Ccách cổ điển là nguy hiểm nếu giá trị enum của bạn không liên quan từ 0). Một cái gì đó như thế này sẽ làm việc:

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

Câu hỏi liên quan của bạn về cú pháp chính xác cho một giá trị enum là bạn chỉ sử dụng giá trị (ví dụ JSON), chứ không phải FormatType.JSONsytax. FormatTypelà một loại và các giá trị enum (ví dụ JSON, XMLvv) là những giá trị mà bạn có thể gán cho loại đó.


127

Bạn không thể làm điều đó một cách dễ dàng. Trong C và Objective-C, enums thực sự chỉ là các hằng số nguyên được tôn vinh. Bạn sẽ phải tự tạo một bảng tên (hoặc với một số lạm dụng tiền xử lý). Ví dụ:

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

Sự nguy hiểm của phương pháp này là nếu bạn thay đổi enum, bạn phải nhớ thay đổi mảng tên. Bạn có thể giải quyết vấn đề này bằng một số lạm dụng tiền xử lý, nhưng nó khó và xấu.

Cũng lưu ý rằng điều này giả sử bạn có hằng số enum hợp lệ. Nếu bạn có một giá trị số nguyên từ một nguồn không đáng tin cậy, bạn cũng cần phải kiểm tra xem hằng số của bạn có hợp lệ hay không, ví dụ bằng cách đưa giá trị "quá khứ tối đa" vào enum của bạn hoặc bằng cách kiểm tra xem nó có nhỏ hơn độ dài mảng không sizeof(FormatType_toString) / sizeof(FormatType_toString[0]).


37
bạn có thể khởi tạo các mảng với các chỉ số rõ ràng, ví dụ: string[] = { [XML] = "XML" }để đảm bảo chuỗi khớp với các enum đúng cách
Christoph

@Christoph: Có, đó là một tính năng C99 được gọi là khởi tạo được chỉ định . Điều đó tốt để sử dụng trong Objective-C (dựa trên C99), nhưng đối với mã C89 chung, bạn không thể sử dụng chúng.
Adam Rosenfield

Có cách nào để đi con đường khác? Ví dụ, lấy enum trở lại cho một chuỗi?
Jameo

1
@Jameo: Vâng, nhưng nó không hoàn toàn đơn giản như thực hiện tra cứu mảng. Bạn sẽ cần phải lặp lại qua FormatType_toString[]mảng và gọi -isEqualToString:từng phần tử để tìm kết quả khớp hoặc sử dụng loại dữ liệu ánh xạ như NSDictionaryđể duy trì bản đồ tra cứu ngược.
Adam Rosenfield

1
Thủ thuật của Max O là tốt về việc quên thêm các mục trong FormatType_toStringmảng.
AechoLiu

50

Giải pháp của tôi:

chỉnh sửa: Cuối cùng tôi đã thêm một giải pháp tốt hơn, sử dụng Modern Obj-C

1.
Đặt tên làm khóa trong một mảng.
Hãy chắc chắn rằng các chỉ mục là các enum thích hợp và theo đúng thứ tự (nếu không có ngoại lệ).
lưu ý: tên là thuộc tính được tổng hợp dưới dạng * _names *;

mã không được kiểm tra để biên dịch, nhưng tôi đã sử dụng kỹ thuật tương tự trong ứng dụng của mình.

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.
Sử dụng Modern Obj-C, chúng ta có thể sử dụng từ điển để gắn các mô tả với các khóa trong enum.
Đặt hàng KHÔNG quan trọng .

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


Cách sử dụng (trong một phương thức thể hiện của lớp):

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



12
Xin lưu ý rằng mỗi khi bạn gọi +[typeDisplayNames], bạn đang tạo lại từ điển. Điều này tốt nếu nó chỉ được gọi một vài lần, nhưng nếu nó được gọi nhiều lần, điều này sẽ rất tốn kém. Một giải pháp tốt hơn có thể là biến từ điển thành một từ đơn, vì vậy nó chỉ được tạo một lần và lưu lại trong bộ nhớ. Bộ nhớ cổ điển so với câu hỏi hóc búa CPU.
Joel Fischer

Hoặc thay đổi nó thành một biến tĩnh, ví dụ: static NSDictionary *dict = nil; if(!dict) dict = @{@(UserTypeParent): @"Parent"}; return dict;Nhận xét sẽ không cho phép bạn ngắt dòng, xin lỗi vì điều đó.
natanavra

29

Kết hợp câu trả lời @AdamRosenfield, bình luận @Christoph và một mẹo khác để xử lý các đơn vị C đơn giản mà tôi đề xuất:

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

Trong trường hợp xấu nhất - như nếu bạn thay đổi enum mà quên thay đổi mảng tên - nó sẽ trả về nil cho khóa này.


12

định nghĩa typedef enum trong tiêu đề lớp:

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

viết một phương thức như thế này trong lớp:

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

có các chuỗi bên trong tệp Localizable.strings :

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

11

Tôi sẽ sử dụng mã thông báo chuỗi # của trình biên dịch (cùng với macro để làm cho tất cả gọn hơn):

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

Điều này hoạt động rất tốt trong C99 - Tôi mới ở C và tôi thấy đây là cách sạch nhất để hoàn thành câu hỏi được hỏi. Tôi cũng đã thêm vào một mặc định trong triển khai của mình cho các mục có thể chưa được xác định. Phương pháp rất sạch sẽ. Cảm ơn về kết quả. Việc sử dụng Macro rất xảo quyệt.
TravisWhidden

8

Tôi thích #definecách làm này:

// Đặt tệp này vào tệp .h của bạn, bên ngoài khối @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];
}

nguồn (nguồn không còn nữa)


@ Daij-Djan nilthì array.count <= enumValuesao?
anneblue

@anneblue sẽ bắt lỗi .. nó sẽ dễ hỏng vì nếu bạn thêm giá trị enum HOẶC giá trị nguyên của giá trị enum sẽ thay đổi. Câu trả lời được chấp nhận sẽ tốt
Daij-Djan

@codercat :( xin lỗi - không chắc điều gì đã xảy ra với trang web đó. Không phải trong cách quay lại Khi máy cũng ...
lindon cáo

Tôi có một câu hỏi nhỏ về câu trả lời trên. Cách chuyển đổi phần tử chuỗi thành kImageType. Tôi cần gọi phương thức imageTypeEnumToString bằng cách truyền chuỗi. Bạn có thể giúp tôi giải quyết vấn đề của mình không.
Ganesh

1
Tôi thích câu trả lời này nhất, bởi vì bạn có các định nghĩa chuỗi ngay bên cạnh enums. Cơ hội ít nhất thiếu một giá trị. Và @Ganesh, để chuyển đổi từ giá trị thô, có thể thực hiện việc này: return (kImageType) [imageTypeArray indexOfObject: rawValue];
Harris

8

Tôi đã tạo ra một loại hỗn hợp của tất cả các giải pháp được tìm thấy trên trang này để tạo ra của tôi, đó là một loại mở rộng enum hướng đối tượng hoặc một cái gì đó.

Trong thực tế nếu bạn cần nhiều hơn chỉ các hằng số (tức là số nguyên), có lẽ bạn cần một đối tượng mô hình (Tất cả chúng ta đang nói về MVC, phải không?)

Chỉ cần tự hỏi mình câu hỏi trước khi sử dụng, tôi có đúng không, trên thực tế, bạn có cần một đối tượng mô hình thực sự, được khởi tạo từ một dịch vụ web, một plist, cơ sở dữ liệu SQLite hoặc CoreData không?

Dù sao ở đây cũng có mã (MPI dành cho "Khởi đầu dự án của tôi", mọi người đều sử dụng tên này hoặc tên của họ, dường như):

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

có vẻ tốt, nhưng bạn đang phân bổ và trả lại từ điển đầy đủ khi bạn chỉ cần một trong những giá trị của nó. Hiệu quả VS Khá mã? phụ thuộc vào những gì bạn muốn và bạn sẽ ổn với điều này nếu bạn không sử dụng chúng nhiều vào mã của bạn như trong một vòng lặp lớn. Nhưng điều này có thể hữu ích với các
enum

5

Giải pháp khác:

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

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

Trong phương pháp của bạn, bạn có thể sử dụng:

NSString *operationCheck = AMZCartServiceOperationValue(operation);

4

Cải thiện câu trả lời @ yar1vn bằng cách loại bỏ phụ thuộc chuỗi:

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

Do đó, khi bạn thay đổi tên mục nhập enum, chuỗi tương ứng sẽ được thay đổi. Hữu ích trong trường hợp nếu bạn không hiển thị chuỗi này cho người dùng.


Bạn có thể giải thích "- xác định
Var biếnName

Với #defines, khi bạn sử dụng # để thay thế, đối số sẽ tự động được gói trong dấu ngoặc kép. Trong C, khi hai chuỗi xuất hiện cạnh nhau trong mã như thế "foo""bar", nó sẽ dẫn đến chuỗi "foobar"khi được biên dịch. Vì vậy, #define VariableName(arg) (@""#arg)sẽ mở rộng VariableName(MyEnum)để được (@"""MyEnum"). Điều đó sẽ dẫn đến chuỗi @"MyEnum".
Chris Doulass

3

Đưa ra một định nghĩa enum như:

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

Chúng ta có thể định nghĩa một macro để chuyển đổi một giá trị enum thành chuỗi tương ứng của nó, như được hiển thị bên dưới.

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

Câu switchlệnh được sử dụng trong khối là để kiểm tra kiểu và cũng để nhận hỗ trợ tự động hoàn thành trong Xcode.

nhập mô tả hình ảnh ở đây nhập mô tả hình ảnh ở đây


2

Tôi đã có một loại liệt kê lớn mà tôi muốn chuyển đổi nó thành một NSDictionarytra cứu. Tôi đã kết thúc bằng cách sử dụng sedtừ thiết bị đầu cuối OSX như:

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

có thể được đọc là: 'chụp từ đầu tiên trên dòng và đầu ra @ (word): @ "word",'

Regex này chuyển đổi enum trong tệp tiêu đề có tên 'ObservationType.h' chứa:

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

vào một cái gì đó như:

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

mà sau đó có thể được gói trong một phương thức bằng cú pháp @{ }object -c hiện đại (như được giải thích bởi @ yar1vn ở trên) để tạo NSDictionarytra cứu:

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

Tấm dispatch_oncenồi hơi chỉ để đảm bảo rằng biến tĩnh được khởi tạo theo cách an toàn cho luồng.

Lưu ý: Tôi đã tìm thấy biểu thức regex sed trên OSX lẻ - khi tôi cố gắng sử dụng +để khớp với 'một hoặc nhiều' nó không hoạt động và phải dùng đến {1,}thay thế


2

Tôi sử dụng một biến thể trong câu trả lời của Barry Walk, theo thứ tự quan trọng:

  1. Cho phép trình biên dịch kiểm tra các mệnh đề trường hợp bị thiếu (không thể nếu bạn có một mệnh đề mặc định).
  2. Sử dụng tên tiêu biểu Objective-C (thay vì tên giống Java).
  3. Tăng một ngoại lệ cụ thể.
  4. Là ngắn hơn.

VÍ DỤ:

- (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 đã thêm câu trả lời xuất sắc nhất vào đây: https://stackoverflow.com/a/24255387/1364257 Xin vui lòng, nâng cấp anh ấy!

Ông sử dụng macro X gọn gàng từ những năm 1960. (Tôi đã thay đổi mã của anh ấy một chút cho ObjC hiện đại)

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

Đó là nó. Sạch sẽ và gọn gàng. Cảm ơn @pixel! https://stackoverflow.com/users/21804/pixel


@AlexandreG cung cấp giải pháp của bạn, người đàn ông. Thật dễ dàng để cá chép với ai đó. Giải pháp này có ưu và nhược điểm rõ ràng cả. Làm cho thế giới tốt hơn với giải pháp của bạn.
voiger

2

Tôi đã kết hợp một số cách tiếp cận ở đây. Tôi thích ý tưởng của bộ tiền xử lý và danh sách được lập chỉ mục.

Không có phân bổ động bổ sung và do trình biên dịch nội tuyến có thể có thể tối ưu hóa việc tra cứu.

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

Trước hết, liên quan đến FormatType.JSON: JSON không phải là thành viên của FormatType, đây là giá trị có thể của loại. FormatType thậm chí không phải là một kiểu hỗn hợp - đó là một vô hướng.

Thứ hai, cách duy nhất để làm điều này là tạo một bảng ánh xạ. Cách phổ biến hơn để làm điều này trong Objective-C là tạo ra một loạt các hằng số đề cập đến "biểu tượng" của bạn, vì vậy bạn sẽ có NSString *FormatTypeJSON = @"JSON"và cứ thế.


1

sau đây cung cấp một giải pháp sao cho thêm một enum mới chỉ cần chỉnh sửa một dòng, công việc tương tự như thêm một dòng trong danh sách 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);
    }
}

Kỹ thuật này được gọi là X-Macro, trong trường hợp ai đó muốn đọc về nó. Điều đó xuất phát từ thực tế là, theo truyền thống, macro FOR_EACH_GENDER () luôn được gọi là X (). Một điều bạn có thể muốn làm là #undef FOR_EACH_GENDER trước khi bạn xác định lại nó với một ý nghĩa mới.
uliwitness

1

Mọi câu trả lời ở đây về cơ bản đều nói cùng một điều, tạo một enum thông thường và sau đó sử dụng một getter tùy chỉnh để chuyển đổi giữa các chuỗi.

Tôi sử dụng một giải pháp đơn giản hơn nhiều, nhanh hơn, ngắn hơn và sạch hơn bằng cách sử dụng Macros!


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

Sau đó, bạn có thể chỉ cần bắt đầu nhập kNam...và tự động hoàn thành sẽ hiển thị danh sách bạn mong muốn!

Ngoài ra, nếu bạn muốn xử lý logic cho tất cả các tên cùng một lúc, bạn có thể chỉ cần nhanh chóng liệt kê các mảng theo thứ tự, như sau:

for (NSString *kName in kNames_allNames) {}

Cuối cùng, việc truyền NSString trong các macro đảm bảo hành vi tương tự như typedef!


Thưởng thức!


0

Nhiều câu trả lời khá tốt.

Nếu bạn theo đuổi một giải pháp chung, Objective C sử dụng một số macro ...

Tính năng chính là nó sử dụng enum như một chỉ mục thành một mảng tĩnh của các hằng số NSString. bản thân mảng được gói vào một hàm để làm cho nó giống với bộ hàm NSStringFromXXX phổ biến hơn trong các API của Apple.

bạn sẽ cần #import "NSStringFromEnum.h"tìm thấy ở đây http://pastebin.com/u83RR3Vk

[EDIT] cũng cần #import "SW+Variadic.h"tìm thấy ở đây http://pastebin.com/UEqTzYLf

Ví dụ 1: xác định hoàn toàn một enped typedef MỚI, với các trình biến đổi chuỗi.

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

trong myfile.m:


 #import "myfile.h"

 implementation_NSString_Enum_Converters(Dispatch_chain_cmd)

sử dụng:

NSString *NSStringFromEnumDispatch_chain_cmd(enum Dispatch_chain_cmd value);

NSStringFromEnumDispatch_chain_cmd(chain_for_c) trả lại @"chain_for_c"

  enum Dispatch_chain_cmd enumDispatch_chain_cmdFromNSString(NSString *value);

enumDispatch_chain_cmdFromNSString(@"chain_previous") trả lại chain_previous

Ví dụ 2: cung cấp các thói quen chuyển đổi cho một enum hiện có cũng thể hiện bằng cách sử dụng chuỗi cài đặt và đổi tên tên được sử dụng trong các hàm.

trong myfile.h


 #import "NSStringFromEnum.h"


 #define CAEdgeAntialiasingMask_SETTINGS_PARAMS CAEdgeAntialiasingMask,mask,EdgeMask,edgeMask

 interface_NSString_Enum_Converters(CAEdgeAntialiasingMask_SETTINGS_PARAMS)

trong 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

Ở đây đang hoạt động -> 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;
}

vì câu trả lời trùng lặp không được phép, đây là giải pháp hoàn chỉnh github.com/ndpiparava/ObjcEnumString
Nitin

-2

Tùy thuộc vào nhu cầu của bạn, bạn có thể thay thế sử dụng các chỉ thị của trình biên dịch để mô phỏng hành vi bạn đang tìm kiếm.

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

Chỉ cần nhớ các thiếu sót của trình biên dịch thông thường, (không phải loại an toàn, sao chép trực tiếp-dán làm cho tệp nguồn lớn hơn)


8
Tôi không nghĩ rằng điều này sẽ làm việc; bất cứ nơi nào #definecó thể nhìn thấy, bạn sẽ không thể sử dụng giá trị enum thực tế (nghĩa là JSONsẽ được thay thế @"JSON"bằng bộ xử lý trước và sẽ dẫn đến lỗi trình biên dịch khi gán cho FormatType.
Barry Wark
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.