我认为我从根本上不了解什么是enum
以及何时使用它。
例如:
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
这里到底声明了什么?
这里声明了三件事:声明了一个匿名的枚举类型,将ShapeType
声明为该匿名枚举的 typedef,并将三个名称kCircle
, kRectangle
和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
声明为匿名枚举的类型定义名称。 ShapeType
实际上只是一个整数类型,仅应用于声明包含声明中列出的值之一的变量(即kCircle
, kRectangle
和kOblateSpheroid
)。但是,您可以通过强制转换为ShapeType
变量分配另一个值,因此在读取枚举值时必须小心。
最后,在全局名称空间中,将kCircle
, kRectangle
和kOblateSpheroid
声明为整数常量。由于未指定特定值,因此将它们分配kCircle
0 开头的连续整数,因此kCircle
为 0, kRectangle
为 1, kOblateSpheroid
为 2。
自 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” 视频。
更新: 在此链接到官方文档。
枚举声明一组有序的值 - typedef 只是为此添加了一个方便的名称。第一个元素是 0,依此类推。
typedef enum {
Monday=1,
...
} WORKDAYS;
WORKDAYS today = Monday;
以上只是 shapeType 标签的枚举。
用户定义的类型,其可能值为kCircle
, kRectangle
或kOblateSpheroid
。但是,枚举内部的值(kCircle 等)在枚举外部可见。记住这一点很重要(例如, int i = kCircle;
是有效的)。
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
,将导致警告Implicit conversion loses integer precision: NSUInteger (aka 'unsigned long') to ShapeType
快速编程更新:
快速地进行了语法更改。
enum ControlButtonID: NSUInteger {
case kCircle , kRectangle, kOblateSpheroid
}
枚举(枚举的缩写)用于枚举一组值(枚举器)。值是用符号(单词)表示的抽象事物。例如,一个基本的枚举可以是
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 前缀的漂亮宏。那应该可以帮助您轻松地定义好的枚举,而且还可以帮助静态分析器在编译之前为您做一些有趣的检查。
好枚举!
typedef
对于重新定义现有变量类型的名称很有用。它提供了一种简短而有意义的方法来调用数据类型。例如:
typedef unsigned long int TWOWORDS;
在此,将 unsigned long int 类型重新定义为 TWOWORDS 类型。因此,我们现在可以通过编写声明 unsigned long int 类型的变量,
TWOWORDS var1, var2;
代替
unsigned long int var1, var2;
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;
那么你可以像这样使用它:
ShapeType shape;
和
enum {
kCircle,
kRectangle,
kOblateSpheroid
}
ShapeType;
现在您可以像这样使用它:
enum ShapeType shape;
枚举用于为枚举元素赋值,这在 struct 中无法完成。因此,每次无需访问完整的变量,我们就可以通过为枚举中的变量赋值来做到这一点。默认情况下,它以 0 赋值开始,但是我们可以为其赋任何值,并且枚举中的下一个变量将被赋值为前一个值 + 1。
typedef 允许程序员将一种 Objective-C 类型定义为另一种。例如,
typedef int 计数器;将计数器类型定义为与 int 类型等效。这大大提高了代码的可读性。