在Objective-C中使用位掩码:iOS如何处理存储在位掩码中的选项?

时间:2013-07-28 22:06:17

标签: ios objective-c c bit-manipulation bitmask

所以,我最近开始学习iOS开发和Objective-C,主要是使用斯坦福大学的iTunes U免费课程。

我最终绊倒了比特掩码,这是iOS API中广泛使用的东西,但我并不是很熟悉。我已经阅读了一些有关它的内容,现在我至少了解它的基础知识。

在斯坦福大学的课程中,我们正在开发一种卡片匹配游戏,比如游戏专注。卡片由按钮表示。正常状态(UIControlStateNormal)表示卡片的背面,而选定状态(UIControlStateSelected)表示其前面(即其内容,称为card.contents的字符串属性,如“一♣“)。如果两张卡匹配,则它们将无法播放,因此在已处于选定状态时,它们将处于禁用状态(UIControlStateDisabled)。 See this image for reference.

Apple documentation about Control States中,我们可以找到定义可能状态的位掩码:

enum {
   UIControlStateNormal               = 0,
   UIControlStateHighlighted          = 1 << 0,
   UIControlStateDisabled             = 1 << 1,
   UIControlStateSelected             = 1 << 2,
   UIControlStateApplication          = 0x00FF0000,
   UIControlStateReserved             = 0xFF000000
};

在某些时候,在斯坦福大学教授讲课时所做的代码中,以下代码用于将card.contents设置为所选状态(卡的正面)和所选状态的标题。残疾州合并(匹配卡):

[cardButton setTitle:card.contents forState:UIControlStateSelected];
[cardButton setTitle:card.contents
            forState:UIControlStateSelected|UIControlStateDisabled];

我不明白的是,为什么我们需要第一线呢?我认为第二个就足够了,因为它是通过使用OR组合两个状态来设置按钮的标题,所以我解释说它已经“覆盖”当卡仅处于选定状态时的情况。

经过一些测试,我显然是错的,所以我不太明白iOS如何处理存储在位掩码中的选项。你能救我吗?

还有一件事:在上面的枚举声明中,前四个常量被定义为01 << 01 << 11 << 2,即{ {1}},012。为什么开发人员将第五个和第六个定义为40x00FF0000,而不是0xFF0000001 << 3

提前致谢!

2 个答案:

答案 0 :(得分:0)

回答你的主要问题:

我的第一个猜测是Apple正在将位掩码与“排除”或“排除”进行比较。 (^)而不是按位和&#39; (&amp;)根据按钮的状态检查要显示的标题。

使用二进制数时,有助于以二进制形式查看这些数字。 &lt;&lt;&lt;操作员是左移。它取第一个数字并将它移到第二个数字空间。

UIControlStateNormal      = 0    = 0000
UIControlStateHighlighted = 1<<0 = 0001
UIControlStateDisabled    = 1<<1 = 0010       
UIControlStateSelected    = 1<<2 = 0100

当您为按钮设置标题时,您正在为该按钮应用位掩码,使用&#39; inclusive或&#39; (|)operator。

UIControlStateSelected|UIControlStateDisabled = 0010|0100

哪个可以

 0010
|0100
 ----
 0110

现在,当你想根据你头衔的面具测试你的状态时。当你用&amp;运算符您将检查结果是否大于0表示成功,您将能够使一个标题适用于多个状态。

 0100 // button state is UIControlStateSelected
&0110 // Button title bit mask
 ----
 0100 // This is greater than 0, success

 0000 // button state is UIControlStateNormal
&0110 // Button title bit mask
 ----
 0000 // This is 0, fail

现在你可以看到问题了。 Apple最初将控制状态设置为0,因此我们不能使用0作为失败的指示,因为在我们为UIControlStateNormal设置标题位掩码的情况下,我们得到:

 0000 // Button state
&0000 // Title bit mask
 ----
 0000 // Failure

DOH!

所以我们使用xor(^}来比较位掩码,0是成功的标志,但这意味着我们不能在标题的位掩码中设置多个状态(除非你可以在某种程度上有多个状态)同时。)

 0000 // State
^0000 // Mask
 ----
 0000 // results is success

 0100 // State
^0100 // Mask
 ----
 0000 // result is success

 0100 // State
^0010 // Mask
 ----
 0110 // Result fails

 0100 // State
^0110 // Mask
 ----
 0010 // Result will always fail because state can only have a single 1

在更现代的框架中,比如SpriteKit,你会注意到文档和示例在1&lt;&lt; 0而不是0时启动状态定义,这样就不会出现这个确切的问题。

回答“还有一件事”

关于从1&lt;&lt;&lt;&lt; 2到0x00FF0000的大跳跃的第二个问题。

UIControlStateReserved是为内部框架使用保留的一组位。它是一个标记,在该值之后的所有内容都是不受限制的。

UIControlStateApplication是开发人员可以在其应用程序中使用的一部分,用于扩展已定义的控件状态并在其代码或自定义控件中使用。它包括从0x00FF0000到0xFF000000的所有位。

Apple在其默认控件状态和开发人员定义的控件状态之间放置一个缓冲区,以便将来的框架更新不会破坏您的应用程序。

您可以定义一个名为UIControlStateAwesomeness的新控制状态,并将其分配给下一个可用位1&lt;&lt; 3,因为这是有道理的,对吧? 但是,Apple发布iOS 11并增加了3个新的控制状态。好吧,他们会按顺序添加它们,您的应用程序现在将在您的应用中定义一个冲突状态。

所以,大缓冲区。我希望这不会太长时间。

答案 1 :(得分:-1)

1<<0  0x00000001

1<<1  0x00000002

1<<2  0x00000004

1<<3  0x00000008  //not 0x00FF0000

1<<4  0x0000000F  //not 0xFF000000

//those four below in fact are in a kind of substate, like gamestate 
UIControlStateNormal               = 0,          I am stll in game screen
UIControlStateHighlighted          = 1 << 0,     I am stil in game screen
UIControlStateDisabled             = 1 << 1,     I am stil in game screen
UIControlStateSelected             = 1 << 2,     I am stil in game screen
//those two are another substate ,
UIControlStateApplication          = 0x00FF0000,  I am in load screen  
UIControlStateReserved             = 0xFF000000   I am in reserved screen

Then there are some mask_num:
inScreen  =     0x000000FF;
inLoadScreen =  0x00FF0000;
inReScreen   =  oxFF000000;
They can use (nowState& mask_num != 0) to detect now state

嗯,我猜。