在NS_OPTIONS中测试多个标志或条件

时间:2014-06-03 22:32:14

标签: objective-c if-statement enums bit-manipulation

这是我想要做的。我有一个简单的NS_OPTIONS设置,如

typedef NS_OPTIONS(NSUInteger, BuildingsPresent) {
    NoBuildings         = 0,
    LadderPresent       = 1 << 0,
    WallPresent         = 1 << 1,
    RoomPresent         = 1 << 2,
    RoomUpgradePresent  = 1 << 3
};

我设置的值如下:

self.buildingPresent |= LadderPresent | WallPresent;

这似乎工作正常,但现在我想像if语句一样测试if语句中的标志:

if (self.buildingPresent & LadderPresent & WallPresent) {

这不能正常工作。如果我将它分解为多个if语句,它似乎确实有效:

if (self.buildingPresent & LadderPresent) {
    if (self.buildingPresent & WallPresent) {
        //do something
    }
}

我也想正确测试缺少某些东西,所以理想的写作方式是:

if (!(self.buildingPresent & RoomPresent) && (self.buildingPresent & LadderPresent & WallPresent) {

这在Objective-C中是否可行?我做错了吗?

2 个答案:

答案 0 :(得分:5)

if (self.buildingPresent & LadderPresent & WallPresent)

这将始终评估为false。

&运算符仅在运算符的两边都设置为1的位位置返回1,而在其他每个位置都返回0。

LadderPresent & WallPresent没有两个位都为1的位置,因此它们将始终为全0。无论你用{0}将全零置零都是零,因此是假的。

如果您打算检查&位和LadderPresent位是否都处于活动状态,则需要WallPresent这些位,然后OR将结果变为变量:

AND

只要 EITHER if (self.buildingPresent & (LadderPresent | WallPresent)) { self.buildingPresent位设置为1,对于LadderPresent的任何值都会返回true。

为了验证 BOTH 是否设置为1,我们必须WallPresent我们的变量到一个掩码,该掩码表示两者都被设置为1,然后看看这些掩码是否等于掩码我们想:

AND

此示例现在仅在BOTH设置为1时才返回true。


测试缺少的正确方法看起来更像是这样:

NSInteger bitMask = (LadderPresent | WallPresent)
if ((self.buildingPresent & bitMask) == bitMask) {

(self.buildingPresent & RoomPresent) == 0 在该位置具有0时返回true,并且当它具有1时返回false。

答案 1 :(得分:3)

您可以直接在dasblinkenlight的答案中使用bit-twiddling表达式,但是如果您编写一个函数来测试多个标志,我认为您的代码会更清晰:

BOOL hasFlags(NSUInteger actualFlags, NSUInteger desiredFlags) {
    return (actualFlags & desiredFlags) == desiredFlags;
}

...

    if (hasFlags(self.buildingPreset, LadderPresent | WallPresent)) {
        ...
    }

(注意:return actualFlags & desiredFlags;中的只是hasFlags。这可以返回不是YES的{​​true}值,{{3} }。)

同样,要检查是否缺少所有指定的标志:

BOOL lacksFlags(NSUInteger actualFlags, NSUInteger forbiddenFlags) {
    return (actualFlags & forbiddenFlags) == 0;
}

...

    if (lacksFlags(self.buildingPresent, RoomPresent)
    && hasFlags(self.buildingPresent, LadderPresent | WallPresent)) {
        ...
    }