Enum defining forms in Objective-C

50,071

Solution 1

enum is as old as C, therefore a part of Objective-C. It is just explicit coding of an int type. It's quite useful for debugging and most newer compilers can make optimizations based on it. (Which you should totally ignore). It's most useful in making your code more readable (to anyone else, or to yourself after you've slept).

typedef enum {
    ...
} NameType ;

would be followed by

NameType name;

and that's typically the preferred style of a typedef,

your second example will not tie the typedef to the values you want to specify should only be of the given type.

Note that this does not prevent you from executing

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

but some compilers might generate a warning in that case,


I ran across Apple's use of the following today:

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

They do this because they really want the NSFetchedResultsChangeType to be of the type they have defined as NSUInteger. This can be an int but it can also be something else. And with values of 1, 2, 3, and 4, it's somewhat irrelevant to us what the type is. But they are coding to a different level of abstraction because they are a tools provider.

You should never look to Apple for coding style hints. If you see something that looks like it's cleaner/better way to code, it usually is. As Kevin mentioned, API stability is of paramount importance for them.


Edit (Jan 2013) If you have access to the WWDC 2012 Session Videos, you should watch Session 405 - Modern Objective-C 6:00-10:00. There is discussion a new syntax in the newer compiler that allows explicit sizing of a type and tight bonding of values to types. (borrowed from C++ 11)

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

Solution 2

The former defines a type name to refer to an enum. This is the way most enums are named in C. The latter is a bit different though, and it's prevalent in the Cocoa frameworks. There's two reasons to use the latter. The first is if your enum defines a bitfield, and you'd want it here because when you're providing a "Name" value you'll be providing a combination of the enum values. In other words, if you say something like

[self doSomethingWithBitfield:(Enum1 | Enum2)]

you're not passing a value of Name but rather an integer that's a combination of the two.

However, Cocoa frameworks use this idiom even for non-bitfield values, for a very good reason: API stability. According to the C standard, the underlying integral type of an enum is requires to be able to contain all values in the enum, but is otherwise chosen by the compiler. This means that adding a new enum value could change the integral type of the enum (e.g. adding -1 can make it signed, adding 6 billion can make it into a long long, etc). This is a bad thing from an API stability standpoint, because the type encoding of methods which take values of this enum could change unexpectedly and potentially break existing code and binaries. In order to prevent this, the Cocoa frameworks generally define the type as being an NSUInteger (or NSInteger if they need negative numbers), so the API and type encodings stay stable.

Share:
50,071
user500
Author by

user500

Updated on January 29, 2020

Comments

  • user500
    user500 over 4 years

    What is the difference between

    typedef enum {
        ...
    } Name;
    

    and

    enum {
        ...
    };
    typedef NSUInteger Name;
    

    ? If functionality is the same, what is the second form good for? Isn't it unnecessarily messy?

  • ArtOfWarfare
    ArtOfWarfare over 11 years
    I'm working on making my own library of functions for iOS right now with the intent of selling them. I assume, then, that I should go against your bolded comment and follow Apple's style?
  • bshirley
    bshirley over 11 years
    @ArtOfWarfare depending on the breadth of your target the answer may vary. If you will also be targeting non-Apple environments, your header files may include all kinds of syntactic obfuscation. If you are only targeting Apple, MY opinion would be to not follow Apple's lead - it's Long Term planning. The only thing it would gain you is support on some hypothetical architecture that no one currently foresees. Others will certainly disagree with me. (aside: Apple will often build onto research architectures - another reason for their architecture agnosticism).
  • Timo
    Timo over 10 years
    Awesome. I was able to use your last code example to get a custom enum value to conform to the UIControlEvents enumeration. This removed a compiler warning when using my custom value for a UIControlEvents type parameter. I used: enum CustomButtonEvent : UIControlEvents { CustomValue = UIControlEventApplicationReserved };. I also added typedef enum CustomButtonEvent CustomButtonEvent to avoid having to type 'enum' every time.
  • anneblue
    anneblue about 10 years
    @Timo The error (that appears when using the enum type in code without writing enum before the custom enum type) disappears when using the typedef enum exactly as apple uses it in its video: typedef enum NSNumberFormatterStyle : NSUInteger {...} NSNumberFormatterStyle; @bshirley would you mind changing your answer to that code?