Every iOS developer has probably come across a property or method in an API that accepts multiple enum values at once, separated by a vertical pipe. How does that work, and how can we do the same?

First, let’s go over what an **enum** is and how to create one. An **enum**, short for **enumeration**, is a user-defined type consisting of a set of named constants called **enumerators**. It is used to group related values in a strongly-typed way. Behind the scenes, each enumerator maps to an **integer**. If we don’t specify explicit integer values, the compiler will automatically assign values sequentially starting from **0**. In this example, we’ll be setting explicit integer values that are **increasing powers of 2** (you’ll see why later). We’ll also be using the new NS_ENUM syntax introduced in iOS 6:

typedef NS_ENUM(NSInteger, MRColor) { MRColorNone = 0, MRColorRed = 1, MRColorBlue = 2, MRColorWhite = 4, MRColorGreen = 8 };

Now let’s imagine invoking a method with several of these color values at once, like this:

[self paint:MRColorRed|MRColorBlue];

In C, we combine multiple enum values by separating them with a vertical pipe. This symbol represents a bitwise **OR** operation. It compares each bit in two values, and for each bit returns **1** if either value is **1**, and returns **0** if not. Here’s what happens if perform an **OR** operation on the included enum values, **MRColorRed** (**1**) and **MRColorBlue** (**2**):

0001 ← MRColorRed (1) 0010 ← MRColorBlue (2) ---- 0011 ← equals 3

So our method receives a color value of **3** as its input. Now, we can use something called the bitwise **AND** operator (**&**). For each bit, it returns **1** if both values are **1**, and returns **0** if not. Let’s perform an **AND** operation on the input (**3**) and both of the included enum values, **MRColorRed** (**1**) and **MRColorBlue** (**2**):

0011 ← input (3) 0001 ← MRColorRed (1) ---- 0001 ← equals 1

0011 ← input (3) 0010 ← MRColorBlue (2) ---- 0010 ← equals 2

Now let’s try an **AND** operation on the input (**3**) and the non-included enum values, **MRColorWhite** (**4**) and **MRColorGreen** (**8**):

0011 ← input (3) 0100 ← MRColorWhite (4) ---- 0000 ← equals 0

0011 ← input (3) 1000 ← MRColorGreen (8) ---- 0000 ← equals 0

Interesting. So for an included enumerator, we get its own value back. For non-included enumerators, we get **0**. So that means that inside our method, we simply need to perform a binary **AND** on the input parameter and every possible enum value to see if it was included. In C, since **0** resolves to **false** and any other number resolves to **true**, we can just put the **AND** operation inside an **if** statement:

- (void) paint:(MRColor)color { if (color & MRColorRed) { //red was included } if (color & MRColorBlue) { //blue was included } if (color & MRColorWhite) { //white was included } if (color & MRColorGreen) { //green was included } … }

This only works because we chose **powers of 2** as our enum values. This allows each enum value to map to a single bit in our input integer value. Think of it as a **row of on-off switches**, where each switch is a bit. This is also called a **bit mask**.

## Bitshift Syntax

Curious developers will notice that the enum definitions in Apple’s header files look very strange. Why is that?

typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) { UIViewAutoresizingNone = 0, UIViewAutoresizingFlexibleLeftMargin = 1 << 0, UIViewAutoresizingFlexibleWidth = 1 << 1, UIViewAutoresizingFlexibleRightMargin = 1 << 2, UIViewAutoresizingFlexibleTopMargin = 1 << 3, UIViewAutoresizingFlexibleHeight = 1 << 4, UIViewAutoresizingFlexibleBottomMargin = 1 << 5 };

The **<<** symbol is also known as the **bitshift operator**. It takes every bit passed to it and shifts it “left” by a given number of spaces. So:

1 << 0: 0001 which is 1 1 << 1: 0010 which is 2 1 << 2: 0100 which is 4 1 << 3: 1000 which is 8

The resulting number values are the same as the powers of two we used! So that means we can alternatively define our enum like this:

typedef NS_OPTIONS(NSUInteger, MRColor) { MRColorNone = 0, MRColorRed = 1 << 0, MRColorBlue = 1 << 1, MRColorWhite = 1 << 2, MRColorGreen = 1 << 3 };

It’s just a different way of expressing the same values in code using sequential numbers instead of increasing powers of 2, which doesn’t look as clean. Finally, with iOS 6 the recommended syntax for defining an enum that contains a bitmask is NS_OPTIONS, not NS_ENUM.

So there you have it! Now you can write properties or methods that accept multiple enum parameters! Enjoy!

Hello,

Thanks for the info :)

if I am not wrong the line :”Here’s what happens if perform an OR operation on the numbers 3 and 1:”

should be ‘Here’s what happens if perform an AND operation on the numbers 3 and 1:’ i Think it is a small typo mistake.

Thanks! Fixed.

if (color | MRColorRed == MRColorRed) <– This is a binary or and incorrect. You can (or should) simply do this: if(color & MRColorRed) <– This returns true when the MRColorRed bit is a 1 and false when it's a 0.

Great suggestion Nick. Much simpler, thanks!

Great article Objective-C enum values. When I started reading and you described using the bitmasking capability of an NS_ENUM, I was thinking, “I’m pretty sure that’s what NS_OPTIONS is for”… and then you covered that right afterwards.

Though I am curious, other than just convention, exactly what is the functional or implementation difference is between the two? NSHipster seems to talk about being able to verify that each NS_OPTION listed is the same type, and another site I found mentioned something about C++ compiler compatibility.

Thanks.

Thanks! This answer seems reasonable to me:

“The special handling NS_OPTIONS for C++ is to avoid requiring explicit casts back to the enum type when the values are or’d with each other. These are required since an expression such as UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight will have a result of type NSUInteger, which cannot be implicitly converted to UIViewAutoresizing.”

http://iamthewalr.us/blog/2012/11/ns_enum-and-ns_options/#comment-44164

Ah…. that makes sense. Thank you for finding that information.