【问题标题】:Different ways of declaring enum in Objective C在 Objective C 中声明枚举的不同方式
【发布时间】:2018-08-05 19:22:00
【问题描述】:

为什么在目标 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;

【问题讨论】:

  • 这个问题不是 Objective-C 特有的,而是 C 的。只有 NS_ENUM 是 Obj-C 中专门提供的便利宏。也许您应该研究typedef 的语义,而不是只关注enum
  • @Willeke 感谢您的链接。我现在了解 NS_ENUM 和 enum 之间的区别,但我仍然不确定 enum 声明的区别。
  • 你点击了 NSHipster 链接吗?

标签: objective-c enums enumeration


【解决方案1】:

以下有什么区别还是都一样?

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

你的第一个例子:

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

是一个原始的 C enum。这声明了一个类型enum WeekDays,其基础类型int,以及5个文字值。

现在 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 变体在这种情况下很弱。然而,许多编译器,包括至少从 v8 开始由 Xcode 使用的编译器,在某些情况下会发出警告(而不是错误),例如如果switch 表达式是enum 类型并且case 标签省略了一些声明的文字或具有声明值之外的值。

给文字明确的值

可以将特定值赋予enum 文字,而不是依赖默认值。例如,将 Monday 的值 1 赋予到 Friday 的值 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 现在是 匿名 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;

至少使用Xcode v8,使用NS_ENUM和上面直接使用typedef在编译器检查和警告方面没有区别。

NS_ENUM 有所作为时

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

当前的 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) 和“枚举”类型 (WeekDays) 之间的赋值可能会产生警告。进一步的switch 语句不会像前三个版本那样被检查,因为它们只是基于NSInteger。这个版本看起来像是模拟 NS_ENUM 的错误尝试,不应该使用(它本身是无效的,只是没有按照它的建议做)。

希望所有的东西都能照亮而不是混淆!

【讨论】:

  • 哇,这是一个非常深入和完整的解释。非常感谢。
猜你喜欢
  • 2010-10-31
  • 1970-01-01
  • 2015-04-26
  • 1970-01-01
  • 1970-01-01
  • 2014-08-22
  • 2010-09-09
相关资源
最近更新 更多