所以,我最近开始学习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如何处理存储在位掩码中的选项。你能救我吗?
还有一件事:在上面的枚举声明中,前四个常量被定义为0
,1 << 0
,1 << 1
和1 << 2
,即{ {1}},0
,1
和2
。为什么开发人员将第五个和第六个定义为4
和0x00FF0000
,而不是0xFF000000
和1 << 3
?
提前致谢!
答案 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
嗯,我猜。