将 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 值传递给方法,我得到一个错误。我遗漏了什么?

140784 次浏览

你不能轻易做到。在 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];

这种方法的危险之处在于,如果更改了枚举,则必须记住更改名称数组。您可以通过滥用一些预处理器来解决这个问题,但是这个问题很棘手,而且很难解决。

还要注意,这里假设您有一个有效的枚举常数。如果您有一个来自不可信源的整数值,您还需要检查常量是否有效,例如,在枚举中包含一个“ past max”值,或者检查它是否小于数组长度 sizeof(FormatType_toString) / sizeof(FormatType_toString[0])

这实际上是一个 C 问题,并不特定于 Objective-C (它是 C 语言的一个超集)。C 中的枚举表示为整数。因此,您需要编写一个函数,该函数返回给定枚举值的字符串。有很多方法可以做到这一点。一个字符串数组,枚举值可以用作数组的索引或映射结构(例如 NSDictionary) ,它将枚举值映射到一个字符串工作,但我发现这些方法不像使转换显式的函数那样清晰(以及数组方法,尽管如果枚举值不是从0开始连续的,经典的 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;
}

关于枚举值的正确语法的相关问题是,只使用值(例如 JSON) ,而不使用 FormatType.JSON语法。FormatType是一个类型,枚举值(例如 JSONXML等)是您可以赋给该类型的值。

首先,关于 FormatType.JSON: JSON 不是 FormatType 的成员,它是该类型的一个可能值。FormatType 甚至不是一个复合类型ーー它是一个标量。

其次,实现这一点的唯一方法是创建一个映射表。在 Objective-C 中更常用的方法是创建一系列引用“符号”的常量,这样就有了 NSString *FormatTypeJSON = @"JSON"等等。

根据您的需要,您可以选择使用编译器指令来模拟您正在寻找的行为。

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

只要记住通常编译器的缺点,(不安全的类型,直接复制粘贴会使源文件变大)

在类头中定义 typedef 枚举:

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.string文件中包含字符串:

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

我的解决办法是:

Edit: 最后我使用 Modern Obj-C 添加了一个更好的解决方案

将名称作为数组中的键 确保索引是适当的枚举 而且顺序正确(否则为异常)。
注意: 名字是合成为 * _ 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. < BR > 使用 Modern Obj-C 我们可以使用字典将描述绑定到枚举中的键。 < BR > 命令不重要

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。

我喜欢 #define的做法:

//将其放在. h 文件中的@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];
}

资源 (资源不再可用)

我有一个很大的枚举类型,我想把它转换成一个 NSDictionary查找。我最终使用了来自 OSX 终端的 sed作为:

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

可以理解为: ‘捕获行中的第一个单词,然后输出@(word) :@“ word”,

这个正则表达式将枚举转换为一个名为‘ Observer ationType.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 regex 表达式很奇怪——当我试图使用 +来匹配“一个或多个”时,它不起作用,不得不使用 {1,}作为替代

我将使用编译器的 # string 标记(与宏一起使其更加紧凑) :

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

许多答案都相当不错。

如果您想要一个通用的、使用某些宏的 Objective C 解决方案..。

关键特性是它使用枚举作为 NSString 常量静态数组的索引。 数组本身被包装成一个函数,使其更像 Apple API 中普遍使用的 NSStringFromXXX 函数套件。

你需要在这里找到 #import "NSStringFromEnum.h" Http://pastebin.com/u83rr3vk

[编辑] 还需要在这里找到 #import "SW+Variadic.h" http://pastebin.com/ueqtzylf

示例1: 使用字符串转换器完全定义一个 NEW 枚举 typedef。

在我的档案里


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

返回 @"chain_for_c"

  enum Dispatch_chain_cmd enumDispatch_chain_cmdFromNSString(NSString *value);

返回 chain_previous

示例2: 为现有枚举提供转换例程 还演示如何使用设置字符串,以及如何重命名函数中使用的类型名。

在我的档案里


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

我使用了巴里 · 沃克的答案的一个变体,按照重要性排序:

  1. 允许编译器检查缺少 case 子句(如果有默认子句则无法检查)。
  2. 使用 Objective-C 典型名称(而不是类似 Java 的名称)。
  3. 引发特定的异常。
  4. 更短。

例如:

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

通过删除字符串依赖性改进@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)];
}

因此,当您更改枚举条目名称时,相应的字符串将被更改。 如果您不打算向用户显示此字符串,则使用。

我混合了这个页面上的所有解决方案来创建我的,它是一种面向对象的枚举扩展 什么的。

实际上,如果您需要的不仅仅是常量(例如整数) ,那么您可能需要一个模型对象(我们都在谈论 MVC,对吗?)

在使用它之前先问自己一个问题,我说的对吗? 事实上,你不需要一个真正的模型对象,从一个 webservice、一个 plist、一个 SQLite 数据库或者 CoreData 初始化吗?

不管怎样,代码来了(MPI 是“我的项目首字母”的缩写,似乎每个人都用这个或者他们的名字) :

返回文章页面

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

下面提供的解决方案使添加新枚举需要 只进行一行编辑,类似于在枚举{}列表中添加一行。

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

这里添加了最精彩的回答: Https://stackoverflow.com/a/24255387/1364257 请投他一票!

他使用的是上世纪60年代的 X 宏

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

就是这样,干净利落。 多亏了这个像素! < a href = “ https://stackoverflow. com/users/21804/象素”> https://stackoverflow.com/users/21804/pixel

另一个解决办法:

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

这里是工作-> 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;
}

给出枚举定义如下:

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

我们可以定义一个宏来将枚举值转换为相应的字符串,如下所示。

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

块中使用的 switch语句用于类型检查,也用于在 Xcode 获得自动完成支持。

enter image description here enter image description here

我在这里综合了几种方法。 我喜欢预处理器和索引列表的想法。

没有额外的动态分配,并且由于内联,编译器可能能够优化查找。

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

这里的每个答案基本上都是一样的,创建一个常规枚举,然后使用自定义 getter 在字符串之间切换。

我采用了一种更简单、更快、更简洁的解决方案ーー使用宏!


#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 的行为!


好好享受吧!

我想我刚刚创造了最优雅的方法来解决这个问题。 (灵感来自@AdamRosenfield)

例如,您可以像下面这样声明枚举:

typedef NS_ENUM(int, MyEnum) {
MyEnumDefault,
MyEnumOff,
MyEnumOn,
MyEnumMixed,
};


static NSString * const __SGEnumMap_MyEnum[] = {
[MyEnumDefault] = @"default",
[MyEnumOff] = @"off",
[MyEnumOn] = @"on",
[MyEnumMixed] = @"mixed"
};
    

SGENUM_DEFINE_ToString(MyEnum)
SGENUM_DEFINE_FromString(MyEnum)

然后,得到两个要在枚举和字符串之间进行转换的函数:

NSString *result = MyEnumToString(MyEnumOn);
NSLog(@"%@", result);
// on
    

MyEnum value = MyEnumFromString(@"off", -1); // -1 as the default value
NSLog(@"%d", result);
// 1

这样可以吗? 下面是一些神奇的宏:

#define SGENUM_DEFINE_ToString(name) NS_INLINE NSString *name##ToString(name value){\
int count = sizeof(__SGEnumMap_##name) / sizeof(NSString *);\
if (value > count || value < 0) return nil;\
return __SGEnumMap_##name[value];\
}


#define SGENUM_DEFINE_FromString(name) NS_INLINE name name##FromString(NSString *input, int defaultValue) {\
int count = sizeof(__SGEnumMap_##name) / sizeof(NSString *);\
for (int i = 0; i < count; i++) {\
NSString *str = __SGEnumMap_##name[i];\
if ([str isEqual:input]) {\
return i;\
}\
}\
return defaultValue;\
}