objective-c typedef를 해당하는 문자열로 변환


141

.h 파일에 typedef가 다음과 같이 선언되었다고 가정합니다.

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

typedef의 숫자 값을 문자열로 변환하는 함수를 만들고 싶습니다. 예를 들어, 메시지 [self toString:JSON]가 전송 된 경우; 'JSON'을 반환합니다.

함수는 다음과 같습니다.

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

덧붙여서,이 구문을 시도하면

[self toString:FormatType.JSON];

typedef 값을 메소드에 전달하기 위해 오류가 발생합니다. 내가 무엇을 놓치고 있습니까?


문제에 대한 명확한 해결책 은 stackoverflow.com/questions/6331762/enum-values-to-nsstring-ios 에서 내 대답을 참조하십시오 .
BooTooMany

4
어쩌면 우리는 열거 형 에서 Swift 언어를 포옹해야합니다 .
Itachi


: 단순히 문자열 변환은 문자열 캐스트 매크로 배열을 확인하는 것이 열거에 대한 사용자 지정 게터를 사용하지 않고 솔루션을 stackoverflow.com/a/53755377/2057171
알버트 렌쇼

답변:


135

이것은 실제로 C 질문이며 Objective-C에만 국한되지는 않습니다 (C 언어의 상위 집합 임). C의 열거 형은 정수로 표시됩니다. 따라서 열거 형 값이 주어진 문자열을 반환하는 함수를 작성해야합니다. 이를 수행하는 방법에는 여러 가지가 있습니다. 열거 형 값을 배열 또는 인덱스 작업에 매핑하는 맵 구조 (예 :)에 대한 인덱스로 사용할 수있는 문자열 배열 NSDictionary이지만 이러한 접근법은 함수만큼 명확하지 않다는 것을 알았습니다. 변환을 명시 적으로 만듭니다 (그리고 C열거 형 값이 0과 일치하지 않으면 고전적인 방법은 위험 하지만 배열 방식입니다 ). 이와 같은 것이 효과가 있습니다.

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

열거 형 값의 올바른 구문에 대한 관련 질문은 sytax가 JSON아닌 값 (예 FormatType.JSON:) 만 사용한다는 것 입니다. FormatType유형 및 열거 값 (예를 들면이다 JSON, XML등) 해당 유형에 할당 할 수있는 값은이.


127

당신은 쉽게 할 수 없습니다. C와 Objective-C에서 열거 형은 실제로 영광스러운 정수 상수입니다. 이름 테이블을 직접 생성해야합니다 (또는 일부 전 처리기 남용). 예를 들면 다음과 같습니다.

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

이 방법의 위험은 열거 형을 변경하면 이름 배열을 변경해야한다는 것입니다. 일부 전 처리기 남용으로이 문제를 해결할 수 있지만 까다 롭고 추악합니다.

또한 이것은 유효한 열거 형 상수가 있다고 가정합니다. 신뢰할 수없는 소스의 정수 값이있는 경우 열거 형에 "과거 최대"값을 포함 시키거나 배열 길이보다 작은 지 확인하여 상수가 유효한지 확인해야합니다 sizeof(FormatType_toString) / sizeof(FormatType_toString[0]).


37
명시 적 인덱스로 배열을 초기화 할 수 있습니다. 예 string[] = { [XML] = "XML" }를 들어 문자열이 열거 형과 올바르게 일치하는지 확인하십시오
Christoph

@Christoph : 그렇습니다. 그것은 지정된 초기화 자라는 C99 기능 입니다. Objective-C (C99 기반)에서 사용하는 것이 좋지만 일반적인 C89 코드에서는 사용할 수 없습니다.
Adam Rosenfield

다른 길로 갈 수있는 방법이 있습니까? 예를 들어, 문자열이 주어지면 열거 형을 다시 가져 옵니까?
Jameo

1
@ Jameo : 예, 그러나 배열 조회를하는 것만 큼 간단하지 않습니다. FormatType_toString[]배열 을 반복 -isEqualToString:하고 각 요소를 호출 하여 일치하는 항목을 찾거나 매핑 데이터 형식 (예 : NSDictionary역 조회 맵 유지)을 사용해야합니다 .
Adam Rosenfield

1
Max O 의 속임수 는FormatType_toString 배열 .
AechoLiu

50

내 해결책 :

편집 : Modern Obj-C

1을 사용하여 끝에 더 나은 솔루션을 추가했습니다 .
이름을 배열의 키로 입력하십시오.
인덱스가 적절한 열거 형인지, 올바른 순서 인지 확인하십시오 (그렇지 않으면 예외).
참고 : names 는 * _names *로 합성 된 속성입니다.

코드는 컴파일을 확인하지 않았지만 앱에서 동일한 기술을 사용했습니다.

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를 사용하면 사전을 사용하여 설명을 열거 형의 키에 연결할 수 있습니다.
주문은 중요하지 않습니다 .

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


사용법 (클래스 인스턴스 메소드에서) :

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



12
를 호출 할 때마다 +[typeDisplayNames]사전을 다시 작성 한다는 점에 유의 하십시오. 몇 번만 호출하면 괜찮지 만 여러 번 호출하면 매우 비쌉니다. 더 좋은 해결책은 사전을 단일 톤으로 만드는 것이므로 한 번만 만들어지고 그렇지 않으면 메모리에 남아 있습니다. 클래식 메모리 대 CPU 수수께끼.
Joel Fischer

또는 정적 변수로 변경하십시오 (예 : static NSDictionary *dict = nil; if(!dict) dict = @{@(UserTypeParent): @"Parent"}; return dict;Comments는 줄 바꿈을 허용하지 않습니다. 죄송합니다.
natanavra 2016 년

29

@AdamRosenfield 답변, @Christoph 주석 및 일반 C 열거 형을 처리하는 또 다른 트릭을 결합하면 다음과 같이 제안합니다.

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

최악의 경우-열거 형을 변경하지만 이름 배열을 변경하지 않는 경우와 같이이 키에 대해 nil을 반환합니다.


12

클래스 헤더에 typedef enum을 정의하십시오.

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

클래스에서 이와 같은 메소드를 작성하십시오.

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

Localizable.strings 파일 안에 문자열이 있습니다 .

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

11

컴파일러의 # 문자열 토큰 (매크로와 함께 더 작게 만들기 위해)을 사용합니다.

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

이것은 C99에서 훌륭하게 작동했습니다. 저는 C에서 처음 왔으며 이것이 질문을 수행하는 가장 깨끗한 방법이라는 것을 알았습니다. 또한 정의되지 않았을 수있는 항목에 대한 구현에서 기본값을 추가했습니다. 매우 깨끗한 방법. 결과 주셔서 감사합니다. 매크로를 매우 교묘하게 사용합니다.
TravisWhidden

8

나는 #define이것을 하는 방법을 좋아한다 :

// @interface 블록 외부의 .h 파일에 저장하십시오.

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

소스 (소스를 더 이상 사용할 수 없음)


@ Daij-Djan nilif 를 반환 하는 것은 array.count <= enumValue어떻습니까?
anneblue

@anneblue는 오류를 잡을 것입니다. 열거 형 값을 추가하거나 열거 형 값의 정수 값이 변경되면 잘못되기 때문에 깨지기 쉽습니다. 허용 된 답변은 좋을 것입니다
Daij-Djan

@codercat :( 미안 - 해당 웹 사이트로 발생하지 않도록 무엇을하지 웨이 백에 때 기계 중 하나 ....
린든 여우

위의 답변에 작은 질문이 있습니다. 문자열 요소를 kImageType으로 변환하는 방법 문자열을 전달하여 imageTypeEnumToString 메서드를 호출해야합니다. 문제를 해결해 줄 수 있습니까?
Ganesh

1
열거 형 바로 옆에 문자열 정의가 있기 때문에이 대답이 가장 좋습니다. 최소값 손실 가능성. 그리고 원시 값에서 변환하기 위해 @Ganesh는 다음을 수행 할 수 있습니다. return (kImageType) [imageTypeArray indexOfObject : rawValue];
Harris

8

이 페이지에서 찾은 모든 솔루션을 혼합하여 내 것을 만들었습니다. 이것은 일종의 객체 지향 열거 형 확장 또는 무언가입니다.

사실 상수 (정수) 이상이 필요한 경우 모델 객체가 필요할 수 있습니다 (모두 MVC에 대해 이야기하고 있습니까?)

이것을 사용하기 전에 스스로에게 질문하십시오. 실제로 웹 서비스, plist, SQLite 데이터베이스 또는 CoreData에서 초기화 된 실제 모델 객체가 필요하지 않습니까?

어쨌든 여기 코드가 있습니다 (MPI는 "내 프로젝트 이니셜"에 대한 것입니다. 모두가이 이름이나 이름을 사용하는 것 같습니다).

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

멋지게 보이지만 값 중 하나만 필요하면 전체 사전을 할당하고 반환합니다. 효율성 대 예쁜 코드? 원하는 것에 달려 있고 거대한 루프처럼 코드에서 많이 사용하지 않으면 이것으로 잘 될 것입니다. 그러나 이것은 예를 들어 서버에서 나오는 "동적"또는 하드 코딩되지 않은 열거 형에 유용 할 것입니다.
user2387149

5

다른 해결책 :

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

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

귀하의 방법으로 다음을 사용할 수 있습니다.

NSString *operationCheck = AMZCartServiceOperationValue(operation);

4

문자열 종속성을 삭제하여 @ yar1vn 답변을 개선했습니다.

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

따라서 열거 형 항목 이름을 변경하면 해당 문자열이 변경됩니다. 이 문자열을 사용자에게 보여주지 않을 경우에 유용합니다.



#defines를 사용하면 대체를 위해 #을 사용할 때 인수가 자동으로 큰 따옴표로 묶습니다. C에서 코드와 같이 두 개의 문자열이 나란히 나타나면 컴파일 할 때 "foo""bar"문자열이 "foobar"됩니다. 따라서로 #define VariableName(arg) (@""#arg)확장 VariableName(MyEnum)됩니다 (@"""MyEnum"). 문자열이 @"MyEnum"됩니다.
Chris Douglass

3

다음과 같은 열거 정의가 주어졌습니다.

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

아래와 같이 열거 형 값을 해당 문자열로 변환하는 매크로를 정의 할 수 있습니다.

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

switch블록에 사용되는 문은 유형 검사를 위해, 또한 엑스 코드의 자동 완성 지원을받을 수 있습니다.

여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오


2

나는 열거 형을 NSDictionary조회 로 변환하고 싶었다 . sedOSX 터미널에서 다음과 같이 사용 했습니다.

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

'라인에서 첫 번째 단어를 캡처하고 @ (word) : @ "word",'

이 정규식은 열거 형을 'ObservationType.h'라는 헤더 파일로 변환합니다.

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

같은 것으로 :

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

그런 다음 현대적인 objective-c 구문을 사용하여 메서드에 래핑하여 @{ }(위의 @ yar1vn에서 설명 함) NSDictionary조회 를 만듭니다 .

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

dispatch_once보일러 플레이트는 정적 변수는 스레드 안전 방식으로 초기화 될 수 있도록한다.

참고 : OSX에서 sed 정규 표현식이 이상하다는 것을 알았 +습니다. '하나 이상'과 일치 시키기 위해 사용하려고 시도했지만 작동하지 않고 {1,}대체품 으로 사용해야 합니다.


2

Barry Walk의 답변에 변형을 사용합니다.

  1. 컴파일러가 누락 된 case 절을 ​​확인할 수 있도록합니다 (기본 절이있는 경우에는 불가능 함).
  2. Java와 같은 이름이 아닌 Objective-C 일반 이름을 사용합니다.
  3. 특정 예외를 발생시킵니다.
  4. 더 짧습니다.

EG :

- (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은 여기에 가장 훌륭한 답변을 추가했습니다 : https://stackoverflow.com/a/24255387/1364257 제발, 그를 찬양하십시오!

그는 1960 년대의 깔끔한 X 매크로를 사용합니다. (나는 현대 ObjC를 위해 그의 코드를 약간 변경했다)

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

그게 다야. 깨끗하고 깔끔합니다. @pixel에 감사합니다! https://stackoverflow.com/users/21804/pixel


@AlexandreG는 솔루션을 제공합니다. 누군가에게 잉어하기 쉽습니다. 이 솔루션에는 확실한 장단점이 있습니다. 귀하의 솔루션으로 세상을 개선하십시오.
voiger

2

여기에 몇 가지 접근 방식을 결합했습니다. 전 처리기 및 색인화 된 목록에 대한 아이디어가 마음에 듭니다.

추가 동적 할당이 없으며 인라인으로 인해 컴파일러가 조회를 최적화 할 수 있습니다.

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

우선 FormatType.JSON과 관련하여 JSON은 FormatType의 멤버가 아니며 가능한 유형 값입니다. FormatType은 복합 형식도 아니며 스칼라입니다.

둘째,이를 수행하는 유일한 방법은 매핑 테이블을 만드는 것입니다. Objective-C에서이 작업을 수행하는 가장 일반적인 방법은 "기호"를 참조하는 일련의 상수를 작성하는 것 NSString *FormatTypeJSON = @"JSON"입니다.


1

다음은 새 열거 형을 추가하기 위해 한 줄만 편집하면되고 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);
    }
}

이 기술을 누군가가 읽고 싶어하는 경우 X- 매크로라고합니다. 이는 전통적으로 FOR_EACH_GENDER () 매크로가 항상 X ()라고 불렀기 때문입니다. 새로운 의미로 재정의하기 전에 #undef FOR_EACH_GENDER하는 것이 좋습니다.
uliwitness

1

여기에있는 모든 대답은 기본적으로 똑같은 것을 말하고 일반 열거 형을 만든 다음 사용자 지정 게터를 사용하여 문자열을 전환합니다.

저는 매크로를 사용하여 더 빠르고 짧고 더 깨끗한 훨씬 간단한 솔루션을 사용합니다!


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

그런 다음 간단히 입력을 시작할 수 있습니다 kNam... 자동 완성 기능이 원하는 목록을 표시합니다!

또한 모든 이름의 논리를 한 번에 처리하려면 다음과 같이 리터럴 배열을 순서대로 빠르게 열거하면됩니다.

for (NSString *kName in kNames_allNames) {}

마지막으로 매크로에서 NSString 캐스팅은 typedef와 유사한 동작을 보장합니다!


즐겨!


0

많은 답변이 상당히 좋습니다.

일부 매크로를 사용하는 일반적인 Objective C 솔루션을 따르는 경우 ...

주요 특징은 열거 형을 NSString 상수의 정적 배열에 대한 인덱스로 사용한다는 것입니다. 배열 자체는 함수에 래핑되어 Apple API에서 널리 사용되는 NSStringFromXXX 함수와 비슷합니다.

당신은 #import "NSStringFromEnum.h"여기 http://pastebin.com/u83RR3Vk 를 찾을 필요가있을 것입니다

[EDIT 또한 필요 #import "SW+Variadic.h"여기 http://pastebin.com/UEqTzYLf

예제 1 : 문자열 변환기를 사용하여 NEW 열거 형 typedef를 완전히 정의하십시오.

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)

myfile.m에서 :


 #import "myfile.h"

 implementation_NSString_Enum_Converters(Dispatch_chain_cmd)

쓰다 :

NSString *NSStringFromEnumDispatch_chain_cmd(enum Dispatch_chain_cmd value);

NSStringFromEnumDispatch_chain_cmd(chain_for_c) 보고 @"chain_for_c"

  enum Dispatch_chain_cmd enumDispatch_chain_cmdFromNSString(NSString *value);

enumDispatch_chain_cmdFromNSString(@"chain_previous") 보고 chain_previous

예 2 : 기존 열거 형에 대한 변환 루틴 제공은 설정 문자열을 사용하고 함수에 사용 된 유형 이름을 바꾸는 방법도 보여줍니다.

myfile.h에서


 #import "NSStringFromEnum.h"


 #define CAEdgeAntialiasingMask_SETTINGS_PARAMS CAEdgeAntialiasingMask,mask,EdgeMask,edgeMask

 interface_NSString_Enum_Converters(CAEdgeAntialiasingMask_SETTINGS_PARAMS)

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

여기 작동합니다-> 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;
}

중복 답변이 허용되지 않으므로 여기에 완전한 솔루션 github.com/ndpiparava/ObjcEnumString
Nitin

-2

필요에 따라 대안으로 컴파일러 지시문을 사용하여 원하는 동작을 시뮬레이션 할 수 있습니다.

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

일반적인 컴파일러 단점을 기억하십시오 (유형 안전하지 않고 직접 복사하여 붙여 넣기하면 소스 파일이 커집니다)


8
나는 이것이 효과가 없을 것이라고 생각한다. 어느 곳이 #define당신이 실제 열거 값을 사용할 수 없습니다, 볼 (즉,은 JSON으로 대체 얻을 것이다 @"JSON"전처리가와에 할당 할 때 컴파일러 오류가 발생합니다 FormatType.
배리 Wark
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.