Declaring and checking/comparing (bitmask-)enums in Objective-C

You know in Cocoa there is this thing, for example you can create a UIView and do:

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

I have a custom UIView with multiple states, which I have defined in an enum like this:

  • Typedef redefinition of UInt32 in MacTypes.h, from definition in CFBase.h
  • C++: How to reuse Encrypted Sqlite database in MFC application which is already in iOS
  • How can I resolve single symbol link error when dynamically linking XCode project to lib4cxx library?
  • Creating Qt 5.1 apps for iOS
  • Compiling Freetype for iPhone SDK (XCode)
  • How to use Superpowered lib in Swift project
  • enum DownloadViewStatus {
      FileNotDownloaded,
      FileDownloading,
      FileDownloaded
    };
    

    For each created subview, I set its tag: subview1.tag = FileNotDownloaded;

    Then, I have a custom setter for the view state which does the following:

    for (UIView *subview in self.subviews) {
      if (subview.tag == viewStatus)
        subview.hidden = NO;
      else
        subview.hidden = YES;
    }
    

    But what I am trying to do, is to allow this:

    subview1.tag = FileNotDownloaded | FileDownloaded;
    

    So my subview1 shows up in two states of my view. Currently, it doesn’t show up in any of those two states since the | operator seems to add the two enum values.

    Is there a way to do that?

    3 Solutions Collect From Internet About “Declaring and checking/comparing (bitmask-)enums in Objective-C”

    Declaring Bitmasks:

    Alternatively to assigning absolute values (1, 2, 4, …) you can declare bitmasks (how these are called) like this:

    typedef enum : NSUInteger {
      FileNotDownloaded = (1 << 0), // => 00000001
      FileDownloading   = (1 << 1), // => 00000010
      FileDownloaded     = (1 << 2)  // => 00000100
    } DownloadViewStatus;
    

    or using modern ObjC’s NS_OPTIONS/NS_ENUM macros:

    typedef NS_OPTIONS(NSUInteger, DownloadViewStatus) {
      FileNotDownloaded = (1 << 0), // => 00000001
      FileDownloading   = (1 << 1), // => 00000010
      FileDownloaded    = (1 << 2)  // => 00000100
    };
    

    (see Abizern’s answer for more info on the latter)

    The concept of bitmasks is to (usually) define each enum value with a single bit set.

    Hence ORing two values does the following:

    DownloadViewStatus status = FileNotDownloaded | FileDownloaded; // => 00000101
    

    which is equivalent to:

      00000001 // FileNotDownloaded
    | 00000100 // FileDownloaded
    ----------
    = 00000101 // (FileNotDownloaded | FileDownloaded)
    

    Comparing Bitmasks:

    One thing to keep in mind when checking against bitmasks:

    Checking for exact equality:

    Let’s assume that status is initialized like this:

    DownloadViewStatus status = FileNotDownloaded | FileDownloaded; // => 00000101
    

    If you want to check if status equals FileNotDownloaded, you can use:

    BOOL equals = (status == FileNotDownloaded); // => false
    

    which is equivalent to:

       00000101 // (FileNotDownloaded | FileDownloaded)
    == 00000100 // FileDownloaded
    -----------
    =  00000000 // false
    

    Checking for “membership”:

    If you want to check if status merely contains FileNotDownloaded, you need to use:

    BOOL contains = (status & FileNotDownloaded) != 0; // => true
    
       00000101 // (FileNotDownloaded | FileDownloaded)
    &  00000100 // FileDownloaded
    -----------
    =  00000100 // FileDownloaded
    != 00000000 // 0
    -----------
    =  00000001 // 1 => true
    

    See the subtle difference (and why your current “if”-expression is probably wrong)?

    While @Regexident has provided an excellent answer – I must mention the modern Objective-C way of declaring Enumerated options with NS_OPTIONS:

    typedef NS_OPTIONS(NSUInteger, DownloadViewStatus) {
      FileNotDownloaded = 0,
      FileDownloading   = 1 << 0,
      FileDownloaded    = 1 << 1
    };
    

    Further Reference:

    • NSHipster
    • I Am The Walrus
    enum DownloadViewStatus {
      FileNotDownloaded = 1,
      FileDownloading = 2,
      FileDowloaded = 4
    };
    

    This will let you perform bitwise OR’s and AND’s effectively.