在 Objective C 中声明枚举的不同方式

Different ways of declaring enum in Objective C

为什么在 objective c 中有这么多不同的方法来声明枚举?这很令人困惑。

下面这些有区别还是都一样?

enum WeekDays{
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday
};

typedef enum : NSUInteger {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday
} WeekDays;

typedef NS_ENUM(NSInteger, WeekDays){
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday
};

enum {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday
};
typedef NSInteger WeekDays;

Is there any difference between the following or are they all the same?

存在一些差异,一些是由于 C - 它是 Objective-C 的基础 - 如果您正在考虑将 Objective-C 代码导入 Swift。

你的第一个例子:

enum WeekDays { Monday, ..., Friday };

是一个原始的Cenum。这声明了一个 type enum WeekDays,其中 底层类型 int,以及 5 个 literal 值。

现在 C 不是强类型语言:这里的字面量值不是 enum WeekDays 类型而是 int 类型;并且 enum WeekDays 类型的变量可以被赋值为 MondayFriday 以外的值,并且可以被赋值给 int 变量而无需强制转换或转换。第一个字面值(此处为 Monday)将具有 int0,随后的值将比前面的字面量大一个值(因此此处 Friday 具有值 4)。示例:

enum WeekDays one;
int two;

one = Monday;
two = Tuesday; // assigning enum literal to int is OK
two *= 42;     // will produce an int value outside of Monday thru Friday
one = two;     // which can be assigned to an enum WeekDays
one = 34;      // int values can also be directly assigned 

所有 enum 变体在这种方式下很弱。然而,许多编译器,包括 Xcode 自至少 v8 以来使用的编译器,在某些情况下会发出警告(而不是错误),例如如果 switch 表达式是 enum 类型并且 case 标签省略了一些声明的文字或具有声明值之外的值。

给文字明确的值

可以为 enum 文字指定特定值,而不是依赖默认值。例如给 Monday1Friday 具有值 5:

enum WeekDays { Monday = 1, ..., Friday };

像往常一样,没有明确值的文字比前面的文字多分配一个。这些值也不需要连续:

enum WeekDays { Monday = 1, Tuesday = 42, Wednesday = 3, Thursday, Friday };

使用 typedef

许多 C 类型声明复杂且难以解析(它们是填充离子测验问题),C typedef 允许特定类型的 别名 被宣布。 typedef 通常与 enum 声明一起使用,以避免在使用类型时必须使用 enum。例如:

typedef enum WeekDays { Monday, ..., Friday } WeekDays;

声明别名 WeekDays 表示 enum WeekDays。例如:

WeekDays one;      // means exactly the same as the previous
                   // declaration for one
enum WeekDays one; // also valid and means the same thing

在上面的声明中看到两次 WeekDays 可能会造成混淆,或者对某些人来说只是打字太多,可以省略:

typedef enum { Monday, ..., Friday } WeekDays;

这与之前的声明略有不同,WeekDays 现在是 anonymous enum 的别名。对于这样的类型,第一种声明形式现在无效:

enum Weekdays one; // invalid, no such enum
WeekDays one;      // valid

更改基础类型

默认情况下 enum 的基础类型是 int。可以指定不同的 integral 类型,该类型必须足够大以容纳文字表示的所有值。整数类型是整数、无符号整数和字符类型。通过在enum标签后添加: <type>来指定底层类型,字面量可以赋予相同类型的特定值。例如:

typedef enum Vowels : char { Letter_A = 'a', ..., Letter_U = 'u' } Vowels;

如上所述,可以使用匿名枚举:

typedef enum : char { Letter_A = 'a', ..., Letter_U = 'u' } Vowels;

使用NS_ENUM

NS_ENUM 是一个 (Apple) Objective-C 便利宏,它扩展为 typedefenum 声明。例如:

typedef NS_ENUM(NSInteger, WeekDays) { Monday, ..., Friday };

扩展为:

typedef enum WeekDays : NSInteger WeekDays;
enum WeekDays : NSInteger  { Monday, ..., Friday };

避免前向声明等同于:

typedef enum WeekDays : NSInteger { Monday, ..., Friday } WeekDays;

使用Xcodev8,至少,使用NS_ENUM和上面直接typedef.

在编译器检查和警告上没有区别

NS_ENUM有所作为时

如果你写的 Objective-C 将被 Swift 使用,那么使用 NS_ENUM 确实会有所不同:使用 NS_ENUM 声明的枚举将作为Swift enum;而直接声明的一个将作为 Swift struct 和全局 read-only 计算属性的集合导入,每个文字一个。

当前的 Apple 文档(Using Swift with Cocoa and Objective-C (Swift 4.0.3 ),可通过 iBooks)

获取

最后,回到你的例子

以上应该能让你找出不同之处:

  1. 默认Cenum,底层类型为int,类型用作enum WeekDays

  2. 别名 C enum,基础类型为 NSUinteger,类型用作 WeekDays

  3. NS_ENUM 生成 enum,底层类型为 NSInteger,类型可以称为 WeekDaysenum WeekDays

  4. 这声明了两个 不同的类型并且可能会产生警告。第一个是没有别名的匿名 enum ,所以以后不能用这种类型引入变量。它引入的文字是 int 类型的。第二个是 NSInteger 的别名。在 64 位系统上,NSInteger 是 64 位,而 int 是 32 位,所以字面量类型 (int) 和 "enum" 类型 (WeekDays) 可能会产生警告。与前三个版本一样,将不会检查进一步的 switch 语句因为它们只是基于 NSInteger。这个版本看起来像是模仿 NS_ENUM 的错误尝试,不应该使用(它本身是无效的,只是没有按照它的建议去做)。

希望所有的启发多于混淆!