【问题标题】:Convert objective-c typedef to its string equivalent将objective-c typedef转换为其等效的字符串
【发布时间】:2010-11-08 20:40:26
【问题描述】:

假设我在我的 .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 enums typedef


【解决方案1】:

这里的每个答案基本上都说同样的话,创建一个常规枚举,然后使用自定义 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 的行为!


享受吧!

【讨论】:

    【解决方案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];
    }
    

    【讨论】:

      【解决方案3】:

      给定一个枚举定义,如:

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

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

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

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 您可以使用显式索引初始化数组,例如string[] = { [XML] = "XML" } 以确保字符串与枚举正确匹配
        • @Christoph:是的,这是一个名为指定初始化程序的 C99 功能。这可以在 Objective-C(基于 C99)中使用,但对于通用 C89 代码,您不能使用它们。
        • 有什么办法可以反其道而行之吗?例如,在给定字符串的情况下取回枚举?
        • @Jameo:是的,但它不像进行数组查找那么简单。您需要遍历 FormatType_toString[] 数组并在每个元素上调用 -isEqualToString: 以查找匹配项,或者使用映射数据类型(例如 NSDictionary)来维护反向查找映射。
        • Max O 的诀窍就是忘记在FormatType_toString 数组中添加条目。
        【解决方案6】:

        另一种解决方案:

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

        【讨论】:

          【解决方案7】:

          @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 提供您的解决方案,伙计。很容易对某人吹毛求疵。这种解决方案既有明显的优点,也有明显的缺点。用您的解决方案让世界变得更美好。
          【解决方案8】:

          以下提供了一个解决方案,以便添加新的枚举需要 只有一行编辑,类似于在枚举 {} 列表中添加单行。

          //------------------------------------------------------------------------------
          // 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-Macro,以防有人想了解它。这是因为传统上 FOR_EACH_GENDER() 宏总是被称为 X()。在用新的含义重新定义它之前,您可能想做的一件事是#undef FOR_EACH_GENDER。
          【解决方案9】:

          我混合了此页面上找到的所有解决方案来创建我的解决方案,它是一种面向对象的枚举扩展或 东西。

          事实上,如果您需要的不仅仅是常量(即整数),您可能还需要一个模型对象(我们都在谈论 MVC,对吧?)

          在使用它之前问自己一个问题,对吗?事实上,你不需要一个真正的模型对象,从 web 服务、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
          

          【讨论】:

          • 看起来不错,但是当您只需要其中一个值时,您正在分配和返回完整的字典。效率 VS 漂亮的代码?取决于你想要什么,如果你不在你的代码上像在一个巨大的循环中那样使用它们,你会很好的。但这对于来自服务器的“动态”或非硬编码枚举可能有用
          【解决方案10】:

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

          source(来源不再可用)

          【讨论】:

          • @Daij-Djan 如果array.count &lt;= enumValue 返回nil 怎么样?
          • @anneblue 会捕获错误..它仍然很脆弱,因为如果您添加枚举值或枚举值的整数值更改,则会出错。接受的答案会很好
          • @codercat :( 抱歉 - 不知道那个网站发生了什么。不是在机器回来的时候......
          • 我对上述答案有一个小问题。如何将字符串元素转换为 kImageType。我需要通过传递字符串来调用 imageTypeEnumToString 方法。你能帮我解决我的问题吗?
          • 我最喜欢这个答案,因为您在枚举旁边有字符串定义。遗漏值的可能性最小。而@Ganesh,要从原始值转换,可以这样做: return (kImageType)[imageTypeArray indexOfObject:rawValue];
          【解决方案11】:

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

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

          【讨论】:

          • 你能解释一下“--定义变量名(arg)(@”“#arg)---并可能给出更好的解决方案吗?
          • 使用#defines,当您使用# 进行替换时,参数会自动用双引号括起来。在 C 语言中,当两个字符串在 "foo""bar" 这样的代码中彼此相邻出现时,编译时会生成字符串 "foobar"。因此,#define VariableName(arg) (@""#arg) 将扩展 VariableName(MyEnum)(@"""MyEnum")。这将产生字符串@"MyEnum"
          【解决方案12】:

          我使用了 Barry Walk 答案的变体,按重要性排序:

          1. 允许编译器检查缺少的 case 子句(如果有默认子句则不能)。
          2. 使用 Objective-C 典型名称(而不是类似 Java 的名称)。
          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!
          }
          

          【讨论】:

            【解决方案13】:

            很多答案都还不错。

            如果您追求的是使用一些宏的通用 Objective C 解决方案...

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

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

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

            示例 1:使用字符串转换器完全定义一个新的枚举 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)
            

            【讨论】:

              【解决方案14】:

              我会使用编译器的 # 字符串标记(连同宏使其更紧凑):

              #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 的新手,我发现这是完成所提问题的最简洁的方法。我还在我的实现中为可能尚未定义的项目添加了默认值。很干净的方法。感谢您的结果。非常巧妙地使用宏。
              【解决方案15】:

              我有一个大型枚举类型,我想将其转换为 NSDictionary 查找。我最终在 OSX 终端上使用了sed

              $ 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,} 作为替代

              【讨论】:

                【解决方案16】:

                我的解决方案:

                编辑:我在最后添加了一个更好的解决方案,使用 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]);
                


                【讨论】:

                • 请注意,每次调用+[typeDisplayNames] 时,您都在重新创建字典。如果只调用几次,这很好,但如果调用多次,这将变得非常昂贵。更好的解决方案可能是使字典成为单例,因此它只创建一次,否则保留在内存中。经典内存与 CPU 的难题。
                • 或者改成静态变量,例如static NSDictionary *dict = nil; if(!dict) dict = @{@(UserTypeParent): @"Parent"}; return dict;评论不会让你换行,对不起。
                【解决方案17】:

                这确实是一个 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 等)是您可以分配给该类型的值。

                【讨论】:

                  【解决方案18】:

                  结合@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。

                  【讨论】:

                    【解决方案19】:

                    在类头中定义 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.strings 文件中包含字符串:

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

                    【讨论】:

                      【解决方案20】:

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

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

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

                      【讨论】:

                      • 我认为这行不通;在#define 可见的任何地方,您将无法使用实际的枚举值(即JSON 将被预处理器替换为@"JSON",并且在分配给FormatType 时会导致编译器错误。
                      【解决方案21】:

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

                      其次,这样做的唯一方法是创建一个映射表。在 Objective-C 中更常见的方法是创建一系列引用您的“符号”的常量,因此您将拥有 NSString *FormatTypeJSON = @"JSON" 等等。

                      【讨论】:

                        猜你喜欢
                        • 2010-10-07
                        • 2014-05-17
                        • 1970-01-01
                        • 2011-07-05
                        • 2015-09-30
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2013-09-01
                        相关资源
                        最近更新 更多