题 Objective-C中的typedef枚举是什么?


我不认为我从根本上理解了什么 enum 是,何时使用它。

例如:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

这里真的被宣布了什么?


1042
2018-04-01 21:59


起源


用户定义的类型是“enum”吗?这就是我的想法,直到我遇到具有多个typedef枚举声明的代码。 - Craig
不,用户定义的类型是ShapeType。阅读typedef: en.wikipedia.org/wiki/Typedef - rampion
Objective-C中的typedef与C中的typedef完全相同。在Objective-C中的枚举与C中的枚举完全相同。这声明了一个包含三个常量的枚举kCircle = 0,kRectangle = 1和kOblateSpheroid = 2,并给枚举类型命名为ShapeType。如果您不知道“typedef”和“enum”的含义,请购买一本关于C的书。 - gnasher729


答案:


这里声明了三件事:声明了一个匿名枚举类型, ShapeType 正被声明为匿名枚举的typedef,以及三个名称 kCirclekRectangle,和 kOblateSpheroid 被宣布为整数常数。

让我们打破它。在最简单的情况下,枚举可以声明为

enum tagname { ... };

这声明了带标记的枚举 tagname。在C和Objective-C(但是  C ++),对此的任何引用 必须 之前是 enum 关键词。例如:

enum tagname x;  // declare x of type 'enum tagname'
tagname x;  // ERROR in C/Objective-C, OK in C++

为了避免不得不使用 enum 关键字无处不在,可以创建一个typedef:

enum tagname { ... };
typedef enum tagname tagname;  // declare 'tagname' as a typedef for 'enum tagname'

这可以简化为一行:

typedef enum tagname { ... } tagname;  // declare both 'enum tagname' and 'tagname'

最后,如果我们不需要能够使用 enum tagname 随着 enum 关键字,我们可以做到 enum 匿名并仅使用typedef名称声明它:

typedef enum { ... } tagname;

现在,在这种情况下,我们宣布 ShapeType 成为匿名枚举的typedef名称。 ShapeType 实际上只是一个整数类型,并且应该仅用于声明包含声明中列出的值之一的变量(即,其中一个 kCirclekRectangle,和 kOblateSpheroid)。你可以分配一个 ShapeType 但是,通过强制转换另一个值,因此在读取枚举值时必须小心。

最后, kCirclekRectangle,和 kOblateSpheroid 在全局命名空间中声明为整数常量。由于未指定特定值,因此将它们分配给以0开头的连续整数,因此 kCircle 是0, kRectangle 是1,和 kOblateSpheroid 是2。


1532
2018-04-01 22:22



很好的解释 - 只是为了添加一件事,struct在C中遵循类似的命名规则(不确定Objective-C)。 - Michael Burr
Objective-C是C的正确超集.C中的所有C结构命名规则在Objective-C中都是有效的。 - sigjuice
真棒。我可以只使用C ++样式枚举,也不需要编写枚举:) - J. Chang
如果您声明它们的文件是.mm文件而不是.m,则可以使用C ++样式枚举。 Objective-C ++非常强大。 - Kevin Hoffman
一旦你了解了这个答案,就值得一看新的NS_ENUM和NS_OPTIONS。这里的教程: nshipster.com/ns_enum-ns_options 在这里: stackoverflow.com/questions/14080750/... - Snowcrash


Apple建议从Xcode 4.4开始定义这样的枚举:

typedef enum ShapeType : NSUInteger {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

它们还提供了一个方便的宏NS_ENUM:

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

这些定义提供更强的类型检查和更好的代码完成。我找不到NS_ENUM的官方文档,但您可以在WWDC 2012会话中观看“Modern Objective-C”视频 这里

更新:链接到官方文档 这里


240
2018-03-06 09:43



关于“枚举改进”的部分从5:58开始 - vikingosegundo
正如另一个答案所评论,请参阅Apple的解释 NS_ENUM 宏观由NSHipster: NSHipster.com/ns_enum-ns_options - Basil Bourque
这是关于NS_ENUM的官方文档的链接: developer.apple.com/library/ios/releasenotes/ObjectiveC/... - YoGiN


枚举声明了一组有序值 - typedef只是为此添加了一个方便的名称。第一个元素是0等

typedef enum {
Monday=1,
...
} WORKDAYS;

WORKDAYS today = Monday;

以上只是shapeType标签的枚举。


47
2018-03-15 16:31





用户定义的类型,其值可能为 kCirclekRectangle, 要么 kOblateSpheroid。但是,enum(kCircle等)中的值在枚举之外是可见的。牢记这一点很重要(int i = kCircle; 例如,有效。


34
2018-04-01 22:04





更新64位更改: 根据 苹果文档 大约64位的变化,

枚举也是类型的:在LLVM编译器中,枚举类型可以   定义枚举的大小。这意味着有些枚举   类型的大小也可能比您预期的大。该   与所有其他情况一样,解决方案是不做任何关于a的假设   数据类型的大小。而是将任何枚举值分配给变量   使用正确的数据类型

所以你必须这样做 用类型创建枚举 如果您支持64位,请使用以下语法。

typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

要么

typedef enum ShapeType : NSUInteger {
   kCircle,
   kRectangle,
   kOblateSpheroid
} ShapeType;

否则,它将导致警告 Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType

更新swift编程:

在swift中,有一个语法变化。

enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }

28
2018-01-29 13:08



如果需要转发声明枚举(NS_ENUM): stackoverflow.com/a/42009056/342794 - lal


枚举是用户定义的数据类型。 已记录的数据类型 枚举数据类型变量只能采用先前声明的值。

enum month { jan = 1, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec };
enum month this_month;

this_month = feb;

在上面的声明中,month声明为枚举数据类型。它由一组值组成,jan到dec。在数值上,jan的值为1,feb的值为2,依此类推。

变量this_month被声明为与month相同的类型,然后被赋予与feb相关联的值。无法为this_month指定在月份声明的初始化列表中指定的值之外的任何值。


25
2017-10-17 12:08





枚举(枚举的缩写)用于枚举一组值(枚举器)。值是由符号(单词)表示的任何抽象事物。 例如,基本枚举可以是

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl };

此枚举称为匿名,因为您没有用于命名它的符号。但它仍然是完全正确的。就这样使用它

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;

好。生活很美好,一切顺利。但有一天你需要重用这个枚举来定义一个新的变量来存储myGrandFatherPantSize,然后你写:

enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize;
enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandFatherPantSize;

但是你有一个编译器错误“重新定义枚举器”。实际上问题是编译器不确定你是第一次枚举而你的第二次描述同样的事情。

然后,如果要在多个位置重用同一组枚举器(此处为xs ... xxxxl),则必须使用唯一名称对其进行标记。第二次使用此设置时,您只需使用标记。但不要忘记,此标记不会替换枚举词,而只会替换枚举器集。然后像往常一样注意使用枚举。喜欢这个:

// Here the first use of my enum
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl } myGrandMotherDressSize; 
// here the second use of my enum. It works now !
enum sizes myGrandFatherPantSize;

您也可以在参数定义中使用它:

// Observe that here, I still use the enum
- (void) buyANewDressToMyGrandMother:(enum sizes)theSize;

你可以说在任何地方重写枚举都不方便,并使代码看起来有点奇怪。你是对的。真正的类型会更好。

这是我们进入峰会的最后一步。通过添加一个typedef,让我们将enum转换为真实类型。哦,最后一件事,你的班级不允许使用typedef。然后在上面定义您的类型。像这样做:

// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type

@interface myClass {
   ...
   size_type myGrandMotherDressSize, myGrandFatherPantSize;
   ...
}

请记住,标签是可选的。然后,在这种情况下,我们不会标记枚举器,只是为了定义一个新类型。然后我们不再需要它了。

// enum definition
typedef enum { xs,s,m,l,xl,xxl,xxxl,xxxxl } size_type;

@interface myClass : NSObject {
  ...
  size_type myGrandMotherDressSize, myGrandFatherPantSize;
  ...
}
@end

如果您使用XCode在ObjectiveC中进行开发,我将让您发现一些以NS_ENUM为前缀的漂亮宏。这应该可以帮助您轻松定义好的枚举,而且还有助于静态分析器在编译之前为您做一些有趣的检查。

好恩生!


23
2018-03-10 18:23



我一直在想“为什么有人会回答已经回答并接受的问题”。男孩,我一直都错了!这是最好的答案,并帮助像我这样的初学者! - rak appdev


typedef 对于重新定义现有变量类型的名称很有用。它提供了调用数据类型的简短而有意义的方法。 例如:

typedef unsigned long int TWOWORDS;

这里,unsigned long int类型被重新定义为TWOWORDS类型。因此,我们现在可以通过写入声明unsigned long int类型的变量,

TWOWORDS var1, var2;

代替

unsigned long int var1, var2;

10
2018-06-18 06:03