目标C中声明枚举的不同方式

Sil*_*ntK 5 enums enumeration objective-c

为什么有这么多不同的方法在目标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;
Run Code Online (Sandbox Code Playgroud)

CRD*_*CRD 14

以下是否有任何区别或它们是否完全相同?

存在差异,一些是由于C - 它们是Objective-C的基础 - 而另一个则是考虑将Objective-C代码导入Swift.

你的第一个例子:

enum WeekDays { Monday, ..., Friday };
Run Code Online (Sandbox Code Playgroud)

是原来的C enum.这声明了一个类型 enum WeekDays,其基础类型int5个字面值.

现在C不是强类型语言:这里的文字值没有类型enum WeekDays,而是类型int; 并且enum WeekDays可以为类型的变量分配除Monday直通之外的值Friday,并将其分配给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 
Run Code Online (Sandbox Code Playgroud)

所有enum变化都在这样弱.然而,在某些情况下,许多编译器(包括至少从v8开始使用的那些编译器)将发出警告(而不是错误),例如,如果switch表达式是一种enum类型,并且case标签要么省略一些声明的文字,要么具有超出声明值的值.

给文字明确的价值观

不是依赖于默认值,而是可以为enum文字赋予特定值.例如,得到Monday的值1通过以Friday具有值5:

enum WeekDays { Monday = 1, ..., Friday };
Run Code Online (Sandbox Code Playgroud)

没有显式值的文字像往常一样被分配比前面的文字多一个.这些值也不需要是连续的:

enum WeekDays { Monday = 1, Tuesday = 42, Wednesday = 3, Thursday, Friday };
Run Code Online (Sandbox Code Playgroud)

用一个 typedef

许多C类型声明很复杂且难以解析(它们是离题测验问题),C typedef允许声明特定类型的别名.A typedef通常与enum声明一起使用,以避免enum在使用类型时使用.例如:

typedef enum WeekDays { Monday, ..., Friday } WeekDays;
Run Code Online (Sandbox Code Playgroud)

声明别名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
Run Code Online (Sandbox Code Playgroud)

WeekDays在上述声明中看到两次可能会让人感到困惑,或者只是为某些人打字太多,而且可以省略:

typedef enum { Monday, ..., Friday } WeekDays;
Run Code Online (Sandbox Code Playgroud)

这与之前的声明略有不同,WeekDays现在是匿名 的别名enum.使用这种类型,第一种声明形式现在无效:

enum Weekdays one; // invalid, no such enum
WeekDays one;      // valid
Run Code Online (Sandbox Code Playgroud)

更改基础类型

默认情况下,a的基础类型enumint.可以指定不同的整数类型,类型必须足够大以容纳文字所代表的所有值.整数类型是整数,无符号整数和字符类型.通过: <type>enum标记之后添加来指定基础类型,并且可以为文字指定相同类型的特定值.例如:

typedef enum Vowels : char { Letter_A = 'a', ..., Letter_U = 'u' } Vowels;
Run Code Online (Sandbox Code Playgroud)

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

typedef enum : char { Letter_A = 'a', ..., Letter_U = 'u' } Vowels;
Run Code Online (Sandbox Code Playgroud)

运用 NS_ENUM

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

typedef NS_ENUM(NSInteger, WeekDays) { Monday, ..., Friday };
Run Code Online (Sandbox Code Playgroud)

扩展为:

typedef enum WeekDays : NSInteger WeekDays;
enum WeekDays : NSInteger  { Monday, ..., Friday };
Run Code Online (Sandbox Code Playgroud)

避免前向声明相当于:

typedef enum WeekDays : NSInteger { Monday, ..., Friday } WeekDays;
Run Code Online (Sandbox Code Playgroud)

至少使用Xcode v8,使用NS_ENUM和直接使用之间的编译器检查和警告没有区别typedef.

NS_ENUM有所作为

如果您正在编写将由Swift使用的Objective-C,那么使用NS_ENUM确实会产生影响:声明使用的枚举NS_ENUM将作为Swift导入enum; 而直接声明的一个将被导入为Swift struct和一个全局只读计算属性的集合,每个文字一个.

为什么存在这种差异在当前的Apple文档中没有解释(使用Swift with Cocoa和Objective-C(Swift 4.0.3),可通过iBooks获得)

最后,回到你的例子

以上应该可以让你找出差异:

  1. 默认C enum,底层类型是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)和"枚举"类型(WeekDays)之间的分配可能会产生警告.进一步的switch陈述不会像之前的三个版本那样进行检查,因为它们只是基于NSInteger.这个版本看起来像是一个不正确的模拟尝试,NS_ENUM不应该使用(它本身是无效的,只是没有做它的建议).

希望所有这些都能让人感到困惑!