【问题标题】:The use of bitmasks in Objective-C: how iOS handles options stored in bitmasks?Objective-C 中位掩码的使用:iOS 如何处理存储在位掩码中的选项?
【发布时间】:2013-07-28 22:06:16
【问题描述】:

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

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

在这门斯坦福课程中,我们正在开发一款纸牌配对游戏,例如“专注”游戏。卡片由按钮表示。正常状态 (UIControlStateNormal) 表示卡片的背面,而选中状态 (UIControlStateSelected) 表示卡片的正面(即其内容,一个名为 card.contents 的字符串属性,如“A♣”)。如果两张卡匹配,它们将变得无法播放,因此它们在已处于选定状态时进入禁用状态 (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 &lt;&lt; 01 &lt;&lt; 11 &lt;&lt; 2,即01、@ 987654336@ 和 4。为什么开发者将第五个和第六个定义为0x00FF00000xFF000000,而不是1 &lt;&lt; 31 &lt;&lt; 4

提前致谢!

【问题讨论】:

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


    【解决方案1】:

    回答你的主要问题:

    我的第一个猜测是,在检查要根据按钮状态显示哪个标题时,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
    

    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

    回答“只是一件事”:

    关于第二个问题,关于从1

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

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

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

    您可以定义一个名为 UIControlStateAwesomeness 的新控件状态并将其分配给下一个可用位 1

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

    【讨论】:

      【解决方案2】:
      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
      

      好吧,我猜。

      【讨论】:

      • 是的,购买为什么开发者决定使用0x00FF00000xFF000000而不是按照之前的模式?
      • @glevco 我现在有一些猜测
      猜你喜欢
      • 1970-01-01
      • 2015-05-21
      • 2023-03-07
      • 2010-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-22
      相关资源
      最近更新 更多