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

What is a typedef enum in Objective-C?

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

例如:

1
2
3
4
5
typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

这里真正宣布的是什么?


这里声明三件事:一个匿名枚举类型被声明,一个匿名枚举的ShapeType被声明为typedef,三个名称kCirclekRectanglekOblateSpheroid被声明为整型常量。

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

1
enum tagname { ... };

这声明了一个带有标记tagname的枚举。在C和ObjuleC(而不是C++)中,任何对这个的引用必须先用EDCOX1的9个关键字。例如:

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

为了避免在任何地方都使用enum关键字,可以创建typedef:

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

这可以简化为一行:

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

最后,如果我们不需要在enum关键字中使用enum tagname,我们可以使enum匿名,并且只使用typedef名称声明它:

1
typedef enum { ... } tagname;

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

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


Apple建议定义这样的枚举,因为Xcode4.4:

1
2
3
4
5
typedef enum ShapeType : NSUInteger {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

它们还提供了一个方便的宏ns_枚举:

1
2
3
4
5
typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

这些定义提供了更强的类型检查和更好的代码完成。我找不到ns_Enum的官方文档,但您可以在这里观看WWDC 2012会议的"现代目标C"视频。

更新:链接到官方文件。


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

1
2
3
4
5
6
typedef enum {
Monday=1,
...
} WORKDAYS;

WORKDAYS today = Monday;

上面只是shapetype标记的枚举。


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


64位更改的更新:根据Apple Docs关于64位更改的信息,

Enumerations Are Also Typed : In the LLVM compiler, enumerated types can
define the size of the enumeration. This means that some enumerated
types may also have a size that is larger than you expect. The
solution, as in all the other cases, is to make no assumptions about a
data type’s size. Instead, assign any enumerated values to a variable
with the proper data type

因此,如果您支持64位的话,您必须按照下面的语法创建具有类型的枚举。

1
2
3
4
5
typedef NS_ENUM(NSUInteger, ShapeType) {
    kCircle,
    kRectangle,
    kOblateSpheroid
};

1
2
3
4
5
typedef enum ShapeType : NSUInteger {
   kCircle,
   kRectangle,
   kOblateSpheroid
} ShapeType;

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

swift编程更新:

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

1
2
3
enum ControlButtonID: NSUInteger {
        case kCircle , kRectangle, kOblateSpheroid
    }


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

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

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

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

好啊。生活很美好,一切都很顺利。但有一天,您需要重用此枚举来定义一个新变量来存储mygrandfatherpantsize,然后编写:

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

但随后会出现编译器错误"重新定义枚举器"。事实上,问题在于编译器不确定您是第一个枚举,而您是第二个枚举,它们描述的是相同的东西。

然后,如果要在多个地方重用同一组枚举器(这里是xs…xxxxl),则必须用唯一的名称对其进行标记。第二次使用此集合时,只需使用标记。但不要忘记,这个标记并不能替换枚举词,而只是一组枚举数。然后注意像往常一样使用枚举。这样地:

1
2
3
4
// 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;

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

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

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

这是我们迈向首脑会议的最后一步。只需添加typedef,我们就可以将枚举转换为实际类型。哦,最后一件事,typedef在你的类中是不允许的。然后定义上面的类型。这样做:

1
2
3
4
5
6
7
8
9
// enum definition
enum sizes { xs,s,m,l,xl,xxl,xxxl,xxxxl };
typedef enum sizes size_type

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

记住标记是可选的。然后,从这里开始,在这种情况下,我们不标记枚举器,而只是定义一个新的类型。那我们就不再需要它了。

1
2
3
4
5
6
7
8
9
// 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-eum的好宏。这将帮助您轻松定义好的枚举,而且还将帮助静态分析器在编译之前为您做一些有趣的检查。

好枚举!


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

1
typedef unsigned long int TWOWORDS;

这里,无符号long int类型被重新定义为twowords类型。因此,我们现在可以通过编写来声明无符号long int类型的变量,

1
TWOWORDS var1, var2;

而不是

1
unsigned long int var1, var2;

1
2
3
4
5
typedef enum {
kCircle,
kRectangle,
kOblateSpheroid
} ShapeType;

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

1
 ShapeType shape;

1
2
3
4
5
6
 enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
}
ShapeType;

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

1
enum ShapeType shape;

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


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

  • k圈是0,
  • Krectangle是1,
  • Koblatespheroid是2。

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

1
2
3
4
5
6
7
8
typedef enum : NSUInteger {
    kCircle, // for your value; kCircle = 5, ...
    kRectangle,
    kOblateSpheroid
} ShapeType;

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

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

1
2
3
4
5
typedef enum {
    kCircle,
    kRectangle,
    kOblateSpheroid
} ShapeType;

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

1
2
3
ShapeType shape1;
ShapeType shape2;
ShapeType shape3;


typedef允许程序员将一个object-c类型定义为另一个。例如,

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


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

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

定义没有约束。这只是一个替代品。它不能限制国家的所有条件。当状态被分配到5时,程序将出错,因为没有匹配的状态。但编译器不会警告状态=5

所以最好这样用

1
2
3
4
5
6
7
typedef enum SampleState {
    SampleStateGood  = 0,
    SampleStateBad,
    SampleStateOther
} SampleState;

SampleState state = SampleStateGood;