Objective-C中定义表单的枚举

36

什么是它们的区别?

typedef enum {
    ...
} Name;
and
enum {
    ...
};
typedef NSUInteger Name;

如果功能相同,第二种形式有什么好处呢?它不是很凌乱吗?


1
第二个从 NSUInteger 中派生类型,而不是第一个。 - user866214
2个回答

84

枚举与 C 一样古老,因此是 Objective-C 的一部分。 它只是对 int 类型的明确编码。 它非常有用于调试,大多数较新的编译器可以基于它进行优化。 (您完全可以忽略这一点)。 它最有用的地方在于使您的代码更易读(对于任何其他人或者当您自己睡过后)。

<code><code><code>typedef enum {
    ...
} NameType ;
</code></code></code>

接下来将会跟随

<code><code>NameType name;
</code></code>

那通常是typedef的首选样式,

你的第二个例子不会将typedef与你想要指定的值绑定在一起,应该仅限于给定类型。

请注意,这并不妨碍您执行操作。

name = 10244; // some non-valid value not listed in the enumeration

但某些编译器可能会在这种情况下生成警告。


我今天遇到了苹果公司使用以下内容:

enum {
NSFetchedResultsChangeInsert = 1,
NSFetchedResultsChangeDelete = 2,
NSFetchedResultsChangeMove = 3,
NSFetchedResultsChangeUpdate = 4
};
typedef NSUInteger NSFetchedResultsChangeType;
他们这样做是因为他们真的希望NSFetchedResultsChangeType的类型与他们定义的NSUInteger类型相同。 这个类型可以是一个int,但也可能是其他类型。对于值为1、2、3和4的情况,这对我们来说不太相关。但是他们正在编写不同抽象级别的代码,因为他们是工具提供者。 你永远不应该从苹果公司寻找编码风格提示。如果你看到了一些看起来更干净/更好的编程方式,那通常就是这样。正如Kevin所提到的,API的稳定性对他们来说至关重要。

编辑(2013年1月) 如果您有访问WWDC 2012会议视频的权限,请观看Session 405 - Modern Objective-C 6:00-10:00。其中介绍了新的语法,可以在较新的编译器中明确设置类型大小并将值与类型紧密结合。(借鉴自C ++ 11)

enum NSFetchedResultsChangeType : NSUInteger {
NSFetchedResultsChangeInsert = 1,
NSFetchedResultsChangeDelete = 2,
NSFetchedResultsChangeMove = 3,
NSFetchedResultsChangeUpdate = 4
};

我现在正在开发自己的iOS函数库,并打算将其出售。那么,我应该不顾你加粗的评论,而是遵循苹果的风格,对吗? - ArtOfWarfare
@ArtOfWarfare 根据你的目标范围,答案可能会有所不同。如果你还将针对非苹果环境进行开发,则你的头文件可能包含各种语法混淆。如果你只针对苹果进行开发,我的建议是不要跟随苹果的步伐 - 这是长期规划。唯一能带给你的好处就是在一些目前没有人预见到的假设架构上得到支持。其他人肯定会不同意我的看法。(另外:苹果经常会基于研究架构进行扩展 - 这也是他们架构不可知性的另一个原因)。 - bshirley
太棒了。我能够使用你上次的代码示例,使自定义枚举值符合UIControlEvents枚举。这消除了在使用自定义值作为UIControlEvents类型参数时的编译器警告。我使用了:enum CustomButtonEvent : UIControlEvents { CustomValue = UIControlEventApplicationReserved };。我还添加了typedef enum CustomButtonEvent CustomButtonEvent以避免每次都要输入“enum”。 - Timo
1
@Timo 当在代码中使用自定义枚举类型时,如果没有在其前面写上 enum 关键字,就会出现错误。但是,当我们像苹果在视频中所示的那样使用 typedef enum 时,这个错误就会消失:typedef enum NSNumberFormatterStyle : NSUInteger {...} NSNumberFormatterStyle; @bshirley,您能否将您的答案更改为这段代码呢? - anneblue

9

前者定义了一个类型名称来引用枚举。这是C中大多数枚举的命名方式。后者有点不同,它在Cocoa框架中很普遍。使用后者有两个原因。第一个原因是如果您的枚举定义了位域,那么您希望在此处使用它,因为当您提供“名称”值时,您将提供枚举值的组合。换句话说,如果您说

[self doSomethingWithBitfield:(Enum1 | Enum2)]

你并没有传递Name的值,而是一个由两者组合而成的整数。

然而,即使对于非位域值,Cocoa框架也使用这种惯用法,原因在于API的稳定性。根据C标准,枚举的基础整型类型需要能够容纳枚举中的所有值,但是编译器可以选择其他方面的类型。这意味着添加一个新的枚举值可能会改变枚举的整型类型(例如,添加-1可以使它变为有符号的,添加60亿可以使其成为long long等)。从API稳定性的角度来看,这是一件糟糕的事情,因为接受此枚举值的方法的类型编码可能会意外地发生变化,并且可能会破坏现有代码和二进制文件。为了防止这种情况发生,Cocoa框架通常将类型定义为NSUInteger(如果需要负数,则为NSInteger),以便API和类型编码保持稳定。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接