2

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

我最终偶然发现了位掩码,这是 iOS API 中广泛使用的东西,但我不是很熟悉。我已经阅读了一些关于它的东西,现在我至少了解了它的基础知识。

在这门斯坦福课程中,我们正在开发一款纸牌配对游戏,例如专注力游戏。卡片由按钮表示。正常状态 ( UIControlStateNormal) 表示卡片的背面,而选定状态 ( UIControlStateSelected) 表示卡片的正面(即其内容,称为 的字符串属性card.contents,如“A♣”)。如果两张牌匹配,则它们将无法使用,因此它们UIControlStateDisabled在已处于选定状态时会进入禁用状态 ( )。请参阅此图像以供参考。

有关 Control States 的 Apple 文档中,我们可以找到定义可能状态的位掩码:

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, and 1 << 2,即 , 0, 1, 2and 4。为什么开发人员将第五个和第六个定义为0x00FF0000and 0xFF000000,而不是1 << 3and 1 << 4

提前致谢!

4

2 回答 2

0

回答你的主要问题:

我的第一个猜测是,在检查要根据按钮状态显示哪个标题时,Apple 将位掩码与“异或”(^) 而不是“按位与”(&) 进行比较。

处理二进制数时,以二进制形式查看这些数字会有所帮助。<< 运算符是左移。它采用第一个数字并将其向左移动第二个空格。

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

当您为按钮设置标题时,您将使用“包含或”(|) 运算符为该按钮应用一个位掩码,用于两种状态。

UIControlStateSelected|UIControlStateDisabled = 0010|0100

结果是

 0010
|0100
 ----
 0110

现在,当您想根据您的头衔掩码测试您的状态时。当您使用 & 运算符执行此操作时,您将检查结果是否大于 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

哦!

所以我们使用 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<<0 而不是 0 开始状态定义,因此不会出现这个确切的问题。

回答“只是一件事”:

关于第二个问题,从 1<<2 到 0x00FF0000 的大跃迁。

UIControlStateReserved 是为内部框架使用而保留的一组位。它是一个标记,该值之后的所有内容都是禁区。

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

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

您可以定义一个名为 UIControlStateAwesomeness 的新控件状态并将其分配给下一个可用位 1<<3,因为这很有意义,对吧?但是,随后苹果发布了 iOS 11 并增加了 3 个新的控制状态。好吧,他们将按顺序添加它们,您的应用现在将在您的应用中定义一个冲突状态。

所以,大缓冲。我希望这不是太啰嗦。

于 2015-12-30T18:15:39.747 回答
-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

好吧,我猜。

于 2013-07-28T22:19:34.650 回答