programing tip

NSString에 대한 열거 형 값 (iOS)

itbloger 2020. 11. 19. 07:54
반응형

NSString에 대한 열거 형 값 (iOS)


여러 값을 보유한 열거 형이 있습니다.

enum {value1, value2, value3} myValue;

내 앱의 특정 지점에서 현재 활성화 된 열거 형 값을 확인하고 싶습니다. NSLog를 사용하고 있지만 열거 형 (value1 / valu2 / valu3 / etc ...)의 현재 값을 NSLog에 대한 NSString으로 표시하는 방법이 명확하지 않습니다.

누군가?


여기에 대한 답변 : 구현에 대한 몇 가지 제안

결론은 Objective-C일반, old C enum를 사용하는 것입니다. 이것은 단지 미화 된 정수 세트입니다.

다음 enum과 같이 주어집니다 .

typedef enum { a, b, c } FirstThreeAlpha;

귀하의 방법은 다음과 같습니다.

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

번역을위한 힙 함수를 제공하지 않고는 enum을 힙에 넣는 것을 좋아하지 않았습니다. 내가 생각 해낸 것은 다음과 같습니다.

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

이렇게하면 필요할 때 쉽게 업데이트 할 수 있도록 열거 형 및 문자열 선언이 서로 가깝게 유지됩니다.

이제 코드의 어느 곳에서나 다음과 같이 열거 형 / 매크로를 사용할 수 있습니다.

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

outputs: The enum value is 'value2'.

요소 인덱스를 보장하기 위해 항상 명시 적으로 시작 (또는 모든) 열거 형 값을 선언 할 수 있습니다.

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

제가 소개 할 것은 제가 사용하는 방식이고, 이전 답변보다 더 좋아 보입니다. (생각합니다)

이해하기 쉽도록 UIImageOrientation 으로 설명하고 싶습니다 .

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;

다음과 같은 방법을 만듭니다.

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

해야 할 일은 다음과 같습니다.

  1. 함수의 이름을 지정하십시오.

  2. enum의 내용을 복사하고 NSArray 사이에 붙여 넣습니다. * arr = @ [ and ]; return (NSString *) [arr objectAtIndex : input];

  3. @, "및 쉼표를 넣어

  4. 이익!!!!


이것은 컴파일러에 의해 검증되므로 실수로 인덱스를 혼동하지 않을 것입니다.

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]

나는 이 문제에 대한 우아한 해결책을 제공하는 웹 사이트 (아래의 예를 가져온)를 발견했다 . 원래 게시물은이 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;
}

enum-> NSString 및 NSString-> enum을 변환해야하는 경우 enum 대신 typedef 및 #define (또는 const NSStrings)을 사용하는 것이 더 간단 할 수 있습니다.

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

그런 다음 다른 NSString과 마찬가지로 "명명 된"문자열로 작동합니다.

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

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

유형 검사의 추가 이점이있는 다른 솔루션을 제공 할 수 있다면 변환, 가독성 및 간결성에서 열거 형 값이 누락 된 경우 경고합니다.

주어진 예에서 다음과 같이 typedef enum { value1, value2, value3 } myValue;할 수 있습니다.

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

참고로. 열거 형을 다음과 같이 선언하는 것이 더 나은 방법입니다.

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

이를 통해 형식 안전성 ( NSInteger이 경우) 을 얻고 예상 열거 형 오프셋 ( = 0) 을 설정합니다 .


아래 솔루션은 전 처리기의 stringize 연산자를 사용하여보다 우아한 솔루션을 제공합니다. 오타에 대한 복원력을 높이기 위해 한 곳에서 열거 형 용어를 정의 할 수 있습니다.

먼저 다음과 같은 방법으로 열거 형을 정의하십시오.

#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

이제 다음과 같은 방법으로 사용하십시오.

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

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

다음을 출력합니다.

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

@pixel의 대답은 나를 올바른 방향으로 가리 켰습니다.


X 매크로를 사용할 수 있습니다-이것에 완벽합니다.

이점 1. 실제 열거 형 값과 문자열 값 간의 관계가 한 곳에 있습니다. 2. 나중에 코드에서 일반 switch 문을 사용할 수 있습니다.

손해 1. 초기 설정 코드는 약간 둔하고 재미있는 매크로를 사용합니다.

코드

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

이제 다음을 수행 할 수 있습니다.

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

이 패턴은 1960 년대부터 존재했습니다 (농담이 아닙니다!) : http://en.wikipedia.org/wiki/X_Macro


다음은 기존 정의의 간단한 복사 및 붙여 넣기로 확장 할 수있는 플러그 앤 플레이 솔루션입니다.

다른 많은 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;
}

다음은 선언의 예입니다.

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

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

다음은 호출의 예입니다.

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

즐겨! ;-)


다음은 Objective-C로 작성된 레거시 프로젝트에서 Swift 코드를 사용해야하는 경우 Objective-C 친화적 인 Enum Struct의 예입니다.

예:

contentType.filename. toString ()

"파일 이름"을 반환합니다.


contentType.filename. rawValue

Int Value, 1을 반환합니다 (구조체의 두 번째 항목 이후).

@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

이것은 오래된 질문이지만 연속적이지 않은 열거 형이 있으면 배열 대신 사전 리터럴을 사용하십시오.

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

요구 사항이 언어 목록을 열거하는 것이라고 가정합니다.

.h 파일에 추가

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

이제 .m 파일에서 다음과 같은 배열을 생성하십시오.

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

그게 다야. 이제 enum을 쉽게 사용하고 배열을 사용하여 enum에 대한 문자열을 가져올 수 있습니다. 예를 들면

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

따라서이 패턴은 NS_ENUM 및 동반 ToString 배열의 승인 된 명명 규칙에 따라 다릅니다. 이 관습을 완전히 따르도록 노력하면 자연스럽게 될 것입니다.


이것은 픽셀 단위의 "X"매크로 포스트와 유사합니다. http://en.wikipedia.org/wiki/X_Macro 링크에 감사드립니다 .

매크로에서 생성 된 코드는 까다 롭고 디버깅하기 어려울 수 있습니다. 대신 "일반"코드에서 사용하는 테이블을 생성하십시오. 많은 사람들이 매크로가 코드를 생성하는 데 반대하는 것을 알고 있으며, 위키에 제시된 "X 매크로"기술이 널리 채택되지 않은 이유 중 하나 일 수 있습니다.

테이블을 생성하면 목록을 확장하기 위해 한 곳만 편집하면되고 디버거에서 테이블을 "스루"할 수 없기 때문에 매크로에 묻혀있는 여러 줄의 코드에 대한 많은 사람들의 이의를 없앨 수 있습니다.

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

  1. 매크로 :

    #define stringWithLiteral(literal) @#literal
    
  2. 열거 형 :

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

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

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

==== 편집 ====

다음 코드를 프로젝트에 복사하고 실행합니다.

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

다음은 작업 코드입니다. 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;
}

참고 URL : https://stackoverflow.com/questions/6331762/enum-values-to-nsstring-ios

반응형