79

你知道在 Cocoa 中有这个东西,例如你可以创建一个UIView并做:

view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

我有一个UIView具有多个状态的自定义,我已经定义enum如下:

enum DownloadViewStatus {
  FileNotDownloaded,
  FileDownloading,
  FileDownloaded
};

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

然后,我有一个视图状态的自定义设置器,它执行以下操作:

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

我想做的是允许这样做:

subview1.tag = FileNotDownloaded | FileDownloaded;

因此subview1,我的观点以两种状态出现。目前,它不会出现在这两种状态中的任何一种中,因为|运算符似乎添加了两个枚举值。

有没有办法做到这一点?

4

4 回答 4

281

声明位掩码:

除了分配绝对值(1, 2, 4, ...),您还可以像这样声明位掩码(如何调用它们):

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 的回答)

位掩码的概念是(通常)用单个位集定义每个枚举值。

因此ORing 两个值执行以下操作:

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

看到细微的差别(以及为什么您当前的“if”表达式可能是错误的)?

于 2013-04-23T11:07:02.777 回答
20

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

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

进一步参考:

于 2013-04-23T11:33:04.247 回答
1
enum DownloadViewStatus {
  FileNotDownloaded = 1,
  FileDownloading = 2,
  FileDowloaded = 4
};

这将让您有效地执行按位 OR 和 AND。

于 2013-04-23T10:39:53.023 回答
1

可用于位掩码检查以提高可读性的有用功能。

BOOL bitmaskContains(NSUInteger bitmask, NSUInteger contains) {
    return (bitmask & contains) != 0;
}
于 2019-03-18T02:49:15.800 回答