【问题标题】:Enum defining forms in Objective-CObjective-C 中的枚举定义形式
【发布时间】:2011-11-17 07:15:39
【问题描述】:

有什么区别

typedef enum {
    ...
} Name;

enum {
    ...
};
typedef NSUInteger Name;

?如果功能相同,那么第二种形式有什么用?这不是不必要的混乱吗?

【问题讨论】:

  • 第二个从 NSUInteger 派生一个类型,而不是第一个。

标签: objective-c ios enums


【解决方案1】:

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

[self doSomethingWithBitfield:(Enum1 | Enum2)]

您传递的不是 Name 值,而是一个整数,它是两者的组合。

然而,Cocoa 框架甚至对非位域值也使用这种习惯用法,这是有充分理由的:API 稳定性。根据 C 标准,枚举的底层整数类型需要能够包含枚举中的所有值,但编译器会另外选择。这意味着添加一个新的枚举值可能会改变枚举的整数类型(例如,添加 -1 可以使其有符号,添加 60 亿可以使其成为 long long 等)。从 API 稳定性的角度来看,这是一件坏事,因为采用此枚举值的方法的类型编码可能会意外更改,并可能破坏现有代码和二进制文件。为了防止这种情况发生,Cocoa 框架通常将类型定义为 NSUInteger(如果需要负数,则为 NSInteger),因此 API 和类型编码保持稳定。

【讨论】:

    【解决方案2】:

    enumC 一样古老,因此是Objective-C 的一部分。 它只是int 类型的显式编码。它对于调试非常有用,大多数较新的编译器都可以基于它进行优化。 (你应该完全忽略)。它最有助于使您的代码更具可读性(对其他人,或在您睡觉后对您自己)。

    typedef enum {
        ...
    } NameType ;
    

    后面是

    NameType name;
    

    这通常是 typedef 的首选样式,

    您的第二个示例将将 typedef 绑定到您要指定的值,该值应仅属于给定类型。

    请注意,这不会阻止您执行

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

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


    我今天遇到了 Apple 对以下内容的使用:

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

    他们这样做是因为他们真的希望NSFetchedResultsChangeType 是他们定义为NSUInteger 的类型。这个可以int,但也可以是别的东西。对于 1、2、3 和 4 的值,我们 与类型无关。但他们正在编码到不同的抽象级别,因为他们是工具提供者。

    您永远不应该向 Apple 寻求编码风格提示。如果您看到一些看起来像是更清洁/更好的编码方式的东西,通常是这样。正如 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 制作自己的函数库,目的是出售它们。那么,我认为我应该反对您的粗体评论并遵循 Apple 的风格?
    • @ArtOfWarfare 取决于目标的广度,答案可能会有所不同。如果您还将针对非 Apple 环境,您的头文件可能包含各种语法混淆。如果你只针对苹果,我的意见是不要跟随苹果的领导——这是长期规划。它唯一能让你获得的是对一些目前没有人预见到的假设架构的支持。其他人肯定会不同意我的看法。 (旁白:Apple 经常会建立在研究架构上——这是他们的架构不可知论的另一个原因)。
    • 太棒了。我能够使用您的最后一个代码示例来获取自定义枚举值以符合 UIControlEvents 枚举。这在将我的自定义值用于 UIControlEvents 类型参数时删除了编译器警告。我用过:enum CustomButtonEvent : UIControlEvents { CustomValue = UIControlEventApplicationReserved };。我还添加了typedef enum CustomButtonEvent CustomButtonEvent 以避免每次都输入“枚举”。
    • @Timo 错误(在代码中使用 enum 类型而在自定义枚举类型之前没有写 enum 时出现)在使用 typedef 枚举时消失,就像苹果在其视频中使用它一样: typedef enum NSNumberFormatterStyle : NSUInteger {...} NSNumberFormatterStyle;@bshirley 您介意更改您对该代码的答案吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多