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

What is a typedef enum in Objective-C?

提问人:Craig 提问时间:4/2/2009 最后编辑:Craig 更新时间:4/13/2022 访问量:466001

问:

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

例如:

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

这里真正宣布了什么?

Objective-C 枚举 typedef

评论

2赞 Craig 4/2/2009
用户定义的类型是否称为“枚举”?这就是我的想法,直到我遇到具有多个 typedef 枚举声明的代码。
8赞 rampion 4/2/2009
不,用户定义的类型是 ShapeType。阅读 typedef : en.wikipedia.org/wiki/Typedef
7赞 gnasher729 3/6/2014
Objective-C 中的 typedef 与 C 中的 typedef 完全相同。Objective-C 中的枚举与 C 中的枚举完全相同。这将声明一个具有三个常量 kCircle = 0、kRectangle = 1 和 kOblateSpheroid = 2 的枚举,并将枚举类型命名为 ShapeType。如果你不知道“typedef”和“enum”是什么意思,那就买一本关于C的书。

答:

34赞 Brian Mitchell 4/2/2009 #1

可能值为 、 或 的用户定义类型。不过,枚举中的值(kCircle 等)在枚举外部是可见的。记住这一点很重要(例如,是有效的)。kCirclekRectanglekOblateSpheroidint i = kCircle;

1580赞 Adam Rosenfield 4/2/2009 #2

这里声明了三件事:声明了一个匿名枚举类型,声明了该匿名枚举的 typedef,以及三个名称 , 和 被声明为整数常量。ShapeTypekCirclekRectanglekOblateSpheroid

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

enum tagname { ... };

这将声明一个带有标记的枚举。在 C 和 Objective-C(但不是 C++)中,任何对此的引用都必须以关键字开头。例如:tagnameenum

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

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

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

这可以简化为一行:

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

最后,如果我们不需要能够与关键字一起使用,我们可以匿名并仅使用 typedef 名称声明它:enum tagnameenumenum

typedef enum { ... } tagname;

现在,在本例中,我们将声明为匿名枚举的 typedef 名称。 实际上只是一个整数类型,并且只能用于声明包含声明中列出的值之一(即 、 和 之一)的变量。但是,您可以通过强制转换为变量分配另一个值,因此在读取枚举值时必须小心。ShapeTypeShapeTypekCirclekRectanglekOblateSpheroidShapeType

最后,、 和 在全局命名空间中声明为整数常量。由于没有指定特定值,因此它们被分配给从 0 开始的连续整数,因此 0、1 和 2。kCirclekRectanglekOblateSpheroidkCirclekRectanglekOblateSpheroid

评论

6赞 Michael Burr 4/2/2009
很好的解释 - 只是为了补充一件事,结构在 C 中遵循类似的命名规则(不确定 Objective-C)。
110赞 sigjuice 4/2/2009
Objective-C 是 C 的适当超集。C 语言中的所有 C 结构命名规则在 Objective-C 中同样有效。
0赞 user4951 5/11/2011
棒。我可以只使用C++样式的枚举,也不需要编写枚举:)
11赞 Kevin Hoffman 6/2/2011
如果声明C++样式枚举的文件是 .mm 文件而不是 .m,则可以使用这些枚举。Objective-C++非常强大。
14赞 Snowcrash 4/22/2013
一旦你明白了这个答案,就值得一看新的NS_ENUM和NS_OPTIONS。教程在这里:nshipster.com/ns_enum-ns_options 和 SO 在这里:stackoverflow.com/questions/14080750/...
51赞 hburde 3/16/2012 #3

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

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

WORKDAYS today = Monday;

以上只是 shapeType 标签的枚举。

268赞 Vlad Grigorov 3/6/2013 #4

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

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

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

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

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


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

评论

13赞 vikingosegundo 3/20/2013
关于“枚举改进”的部分从 5:58 开始
5赞 Basil Bourque 9/6/2013
正如对另一个答案的评论,请参阅 NSHipster 对 Apple 宏的解释:NSHipster.com/ns_enum-ns_optionsNS_ENUM
1赞 YoGiN 9/7/2014
这是有关NS_ENUM的官方文档的链接:developer.apple.com/library/ios/releasenotes/ObjectiveC/...
27赞 Vincent Zgueb 3/11/2013 #5

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

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,让我们将枚举转换为真实类型。哦,最后一件事,你的类中不允许使用 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

如果你在 Objective-C 中使用 XCode 进行开发,我会让你发现一些以 NS_ENUM 为前缀的不错的宏。这应该可以帮助您轻松定义良好的枚举,此外,还将帮助静态分析器在编译之前为您做一些有趣的检查。

好枚举!

评论

0赞 rak appdev 3/13/2017
我一直在想“为什么有人会回答一个已经回答和接受的问题”。男孩,我一直都错了!这是最好的答案,对像我这样的初学者有帮助!
10赞 Rajneesh071 6/18/2013 #6

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

typedef unsigned long int TWOWORDS;

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

TWOWORDS var1, var2;

而不是

unsigned long int var1, var2;
5赞 Vivek Sehrawat 12/25/2013 #7
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

然后你可以像这样使用它:-

 ShapeType shape;

 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} 
ShapeType;

现在你可以像这样使用它:-

enum ShapeType shape;
31赞 Mani 1/29/2014 #8

针对 64 位更改的更新:根据 apple docs 关于 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

swift-programming 的更新:

在 swift 中,语法发生了变化。

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

评论

0赞 lal 10/18/2017
如果需要转发声明枚举 (NS_ENUM):stackoverflow.com/a/42009056/342794
3赞 Priyanka Naik 3/16/2014 #9

枚举用于为枚举元素赋值,这在结构中是无法完成的。因此,每次我们都可以通过在枚举中分配给变量的值来访问完整的变量,而不是访问完整的变量。默认情况下,它以 0 赋值开头,但我们可以为其赋值任何值,枚举中的下一个变量将被赋值,即前一个值 +1。

2赞 user4398701 12/28/2014 #10

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

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

2赞 Yogeesh H T 11/16/2015 #11

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

typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

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

ShapeType shape1; 
ShapeType shape2; 
ShapeType shape3;
4赞 Bilal Arslan 3/30/2016 #12

您可以使用以下格式,Raw 默认值从 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
1赞 Marcus Thornton 6/21/2018 #13

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

#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;