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

前端 未结 4 588
旧时难觅i
旧时难觅i 2020-12-07 06:51

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

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIV         


        
相关标签:
4条回答
  • 2020-12-07 07:35

    Useful function you can use for bitmask checking to improve readability.

    BOOL bitmaskContains(NSUInteger bitmask, NSUInteger contains) {
        return (bitmask & contains) != 0;
    }
    
    0 讨论(0)
  • 2020-12-07 07:41

    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)?

    0 讨论(0)
  • 2020-12-07 07:45

    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
    0 讨论(0)
  • 2020-12-07 07:47
    enum DownloadViewStatus {
      FileNotDownloaded = 1,
      FileDownloading = 2,
      FileDowloaded = 4
    };
    

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

    0 讨论(0)
提交回复
热议问题