2013-04-23 63 views
71

你知道,在可可有这个东西,比如你可以创建一个UIView做:声明和检查/比较(bitmask-)枚举在Objective-C

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 

我有一个自定义UIView多状态,这是我在enum定义是这样的:

enum DownloadViewStatus { 
    FileNotDownloaded, 
    FileDownloading, 
    FileDownloaded 
}; 

对于每个所创建的子视图中,我设置其tagsubview1.tag = FileNotDownloaded;

然后,我有一个针对执行以下操作视图状态的定制的setter:

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

什么,我试图做,是为了让这样的:

subview1.tag = FileNotDownloaded | FileDownloaded; 

所以我subview1出现在我的观点的两个状态。目前,它并不出现在这两个州中的任何一个,因为|运营商似乎添加了两个枚举值。

有没有办法做到这一点?

+0

你的'(subview.tag == viewStatus)'看起来不对我。应该是'((subview.tag&viewStatus)!= 0x0)',除非你想检查确切的匹配。在这种情况下,你首先不需要位掩码,但只是一个普通的旧枚举。看到我的答案的后半部分。 – Regexident 2013-04-23 11:17:58

回答

259

声明位掩码:

或者到指定的绝对值(124 ......),你可以声明bitmasks(这些是如何称呼)这样的:

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

或利用现代ObjC的NS_OPTIONS/NS_ENUM宏:

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

(参见Abizern's answer关于后者的详细信息)

位屏蔽的概念是(通常)以单个比特组定义每个枚举值。

因此OR荷兰国际集团的两个值执行以下操作:

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

这相当于:

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

比较位掩码:

有一件事对位掩码检查时要牢记:

检查确切的相等性:

让我们假设状态这样的初始化:

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

如果你想检查是否status等于FileNotDownloaded,你可以使用:

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

这相当于:

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

检查“会员制”:

如果你想检查是否status仅仅包含FileNotDownloaded,你需要使用:

BOOL contains = (status & FileNotDownloaded) != 0; // => true 

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

见的细微差别(为什么你目前的“如果” -expression是可能是错的)?

+0

@Abizern:谢谢!认为这个问题值得比以前提供的更多解释。 – Regexident 2013-04-23 11:19:15

+0

优秀的答案! – horseshoe7 2013-11-26 11:01:55

+0

是的,但你正在格式化二进制值为十六进制值(前面有0x)。位掩码在位级别上工作。简单的错误,我相信你甚至没有注意到它。但有人可能会考虑这一点,并且错误地认为每个枚举最多可以有8个选项,而实际上最多可以有32个不同的选项。更正: 'FileNotDownloaded =(0x1 << 0), // =>%...00000001'等 – 2013-11-28 20:49:22

1
enum DownloadViewStatus { 
    FileNotDownloaded = 1, 
    FileDownloading = 2, 
    FileDowloaded = 4 
}; 

这将让你可以有效地执行按位OR或AND。

+4

定义值的标准方法是'1 << 0','1 << 1','1 << 2'等。这就说明你正在使用位和掩码。 – 2013-04-23 10:58:01

+1

http://nshipster.com/ns_enum-ns_options/值得一读 – 2013-04-23 11:13:20

+1

@AhmedAlHafoudh:文章并没有解决OP的第二个问题:使用位掩码(而不是简单地声明它们)。看到我的答案。 – Regexident 2013-04-23 11:15:44

18

虽然@Regexident提供了一个很好的答案 - 我必须提到声明枚举选项与NS_OPTIONS现代Objective-C的方式:

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

进一步参考:

+0

是的NS_ENUM和NS_OPTION宏很棒。 – uchuugaka 2013-11-29 15:55:19