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


1087

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

例如:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

这里到底声明了什么?


2
用户定义的类型是否称为“枚举”?这就是我的想法,直到遇到带有多个typedef枚举声明的代码。
Craig

8
不,用户定义的类型是ShapeType。阅读有关typedef的内容:en.wikipedia.org/wiki/Typedef

6
Objective-C中的typedef与C中的typedef完全相同。而Objective-C中的枚举与C中的枚举完全相同。这声明了一个具有三个常数kCircle = 0,kRectangle = 1和kOblateSpheroid =的枚举。 2,并将枚举类型命名为ShapeType。如果你不知道什么“类型定义”和“枚举”的意思,买了一本有关C.
gnasher729

Answers:


1565

三件事正在这里声明:匿名枚举类型声明,ShapeType在声明该匿名枚举一个typedef和三个名字kCirclekRectanglekOblateSpheroid被声明为整型常量。

让我们分解一下。在最简单的情况下,枚举可以声明为

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 tagnameenum关键字,则可以将其设为enum匿名并仅使用typedef名称进行声明:

typedef enum { ... } tagname;

现在,在这种情况下,我们声明ShapeType是匿名枚举的类型定义名称。 ShapeType实际上只是一个整数类型,且只能用于声明持有在声明中列出的其中一个值(也就是一个变量kCirclekRectanglekOblateSpheroid)。但是,您可以ShapeType通过强制转换为变量分配另一个值,因此在读取枚举值时必须小心。

最后kCirclekRectanglekOblateSpheroid被声明为全局命名空间的整型常量。由于未指定任何特定值,因此会将它们分配给以0开头的连续整数,kCircle即0、1 kRectanglekOblateSpheroid2。


6
很好的解释-只需添加一件事,struct就遵循C中类似的命名规则(不确定Objective-C)。
Michael Burr

109
Objective-C是C的适当超集。C中的所有C结构命名规则在Objective-C中同样有效。
sigjuice

太棒了 我可以只使用C ++样式枚举,也不需要编写枚举:)
user4951 2011年

11
如果声明它们的文件是.mm文件而不是.m,则可以使用C ++样式枚举。Objective-C ++非常强大。
凯文·霍夫曼

14
一旦您掌握了这个答案,就值得看看新的NS_ENUM和NS_OPTIONS。教程在这里:nshipster.com/ns_enum-ns_options并因此在这里:stackoverflow.com/questions/14080750/...
Snowcrash

254

Xcode 4.4起,Apple建议像这样定义枚举:

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

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

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

这些定义提供了更强大的类型检查和更好的代码完成。我找不到的正式文档NS_ENUM,但是您可以在此处观看WWDC 2012会议的“现代Objective-C”视频。


更新
链接到此处的官方文档。


13
关于“枚举改进”的部分始于5:58
vikingosegundo

5
如对另一答案的评论,请参阅NS_ENUMNSHipster 对苹果宏的解释:NSHipster.com/ns_enum-ns_options
Basil Bourque


50

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

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

WORKDAYS today = Monday;

以上只是shapeType标签的枚举。


34

具有的可能值的用户定义的类型kCirclekRectanglekOblateSpheroid。但是,枚举内部的值(kCircle等)在枚举外部可见。记住这一点很重要(int i = kCircle;例如,有效)。


30

64位更改的更新: 根据Apple文档中有关64位更改的内容,

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

因此,如果支持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

快速编程更新:

快速地进行了语法更改。

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

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

25

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

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),则必须使用唯一的名称对其进行标记。第二次使用此设置时,只需使用标签。但是请不要忘记,此标记不会代替枚举词,而只是代替枚举器集。然后请照常使用enum。像这样:

// 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,我们可以将枚举转换为实型。哦,最后一件事,您的课程中不允许使用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在Objective-C中进行开发,则可以发现带有NS_ENUM前缀的漂亮宏。这应该可以帮助您轻松地定义好的枚举,而且还可以帮助静态分析器在编译之前为您做一些有趣的检查。

好枚举!


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

10

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

typedef unsigned long int TWOWORDS;

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

TWOWORDS var1, var2;

代替

unsigned long int var1, var2;

7
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

那么你可以像这样使用它:

 ShapeType shape;

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

现在您可以像这样使用它:

enum ShapeType shape;

3

枚举用于为枚举元素赋值,这是在struct中无法完成的。因此,每次无需访问完整的变量,我们就可以通过为枚举中的变量赋值来做到这一点。默认情况下,它以0赋值开始,但是我们可以为其赋任何值,并且枚举中的下一个变量将被赋值为前一个值+1。


3

您可以使用以下格式,原始默认值从0开始,因此

  • kCircle为0,
  • kRectangle为1,
  • kOblateSpheroid为2。

您可以分配自己的特定起始值。

typedef enum : NSUInteger {
    kCircle, // for your value; kCircle = 5, ...
    kRectangle,
    kOblateSpheroid
} ShapeType;

ShapeType circleShape = kCircle;
NSLog(@"%lu", (unsigned long) circleShape); // prints: 0

2

typedef允许程序员将一种Objective-C类型定义为另一种。例如,

typedef int计数器;将计数器类型定义为与int类型等效。这大大提高了代码的可读性。


2

Typedef是C和C ++中的关键字。它用于为基本数据类型(char,int,float,double,struct和enum)创建新名称。

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

它在这里创建枚举数据类型ShapeType,我们可以为枚举类型ShapeType编写新名称,如下所示

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;

1

枚举可以减少许多类型的“错误”,并使代码更易于管理

#define STATE_GOOD 0
#define STATE_BAD 1
#define STATE_OTHER 2
int STATE = STATE_OTHER

该定义没有约束。这仅仅是替代。它不能限制状态的所有条件。将STATE分配给5时,程序将出错,因为没有匹配的状态。但是编译器不会警告STATE = 5

所以最好这样使用

typedef enum SampleState {
    SampleStateGood  = 0,
    SampleStateBad,
    SampleStateOther
} SampleState;

SampleState state = SampleStateGood;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.