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

.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 값을 메소드에 전달하기 위해 오류가 발생합니다. 내가 무엇을 놓치고 있습니까?



답변

이것은 실제로 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등) 해당 유형에 할당 할 수있는 값은이.


답변

당신은 쉽게 할 수 없습니다. 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]).


답변

내 해결책 :

편집 : 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]);


답변

@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을 반환합니다.


답변

클래스 헤더에 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";


답변

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

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


답변

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

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