将NSUInteger分配给BOOL概念理解

我正在努力寻找BOOL概念的一个很好的答案。 据我所知,零是一个错误的值,非零是一个真正的值。 想到这一点,我把string长度分配到BOOLvariables。 现在,这对iOS> 6很好。在iOS 6我看到奇怪的结果。 对于奇数长度的string,isEnabled为true,但对于长度均匀的string,isEnabled为turing False。

BOOL isEnabled = myString.length; 

请帮我理解这一点。 当然,现在我已经把expression式分配给BOOLvariables,像这样:

 BOOL isEnabled = myString.length > 0; 

准确的代码:

 - (void)textViewDidChange:(UITextView *)iTextView { self.navigationItem.rightBarButtonItem.enabled = [[self.noteTextView.text trim] length]; } 

PS:如上所述,myString的长度正在改变。 从'a'到'ab'到'abc'等

但是,我不明白iOS 6的行为只启用奇数的button。 我很想知道根本原因。

为了解释观察到的行为,有两个技术细节需要解释:Objective-C的BOOL和UIKit的实现细节。

BOOLtypes

不同的行为实际上与iOS 版本无关,而与设备的架构无关。 iOS SDK如何定义32位和64位体系结构的BOOL是有区别的。 请参阅objc.h摘录:

 #if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__ typedef bool BOOL; #else typedef signed char BOOL; #endif 

所以在32位BOOL可以有0到255之间的任何值,而在64位它是编译器强制只有值0或1.您可以轻松地尝试通过在模拟器上运行以下行,设置为iPhone 4s( 32位)或iPhone 6(64位)。

 NSLog(@"%d", (BOOL)2); 

这是为什么你在不同的设备上看到不同的行为的解释。 但是奇怪的事从哪里来呢?

UIBarButtonItem的实现细节

还有一些细微的技术细节。 您实际上正在设置UIBarButtonItemenabled属性。

苹果喜欢使用节省空间的scheme在UI组件中存储标志。 BOOL (在32位和64位体系结构上)总是使用至less一个字节,但只需要一位信息。 所以他们使用位域来存储实际的值。

摘录自iOS SDK 8.4 UIBarButtonItem.h (缩略为清晰):

 @interface UIBarButtonItem : UIBarItem { struct { unsigned int enabled:1; } _barButtonItemFlags; } 

魔术是:1 _barButtonItemFlags结构中enabled字段后面的:1 。 这定义了宽度为1的位域。 要连接enabled属性与这个位域,他们必须实现自定义访问器。 这是一个设置器的例子:

 - (void)setEnabled:(BOOL)enabled { _barButtonItemFlags.enabled = enabled; } 

那么当我们这样做时会发生什么:

 someBarButtonItem.enabled = 2; 

编译器明白它必须使用参数2来调用setEnabled:方法。

在64位体系结构中, 2将被转换为_Bool ,其中标准表示这必须导致值为1 。 在32位系统上,情况并非如此,在调用方法之前,将原始值保留在原来的位置。

setEnabled:内部setEnabled:该值被分配给宽度为1的无符号整数。C标准说,当分配一个宽度更大的无符号整数时,其余的位将被丢弃。 结果是setEnabled:只在_barButtonItemFlags.enabled存储参数的最低位。 最低位是一个奇数,偶数是零。

结论

以上所有行为均在标准提供的语义范围内。 没有涉及不确定的行为。 这只是一个不幸的事实, BOOL的预期行为不同于你在32位体系结构上的实际行为。

在早些时候, BOOL被实现为整数types。 因此,通过这样的实现,可以给它赋值> 1并读回。 但是从一开始这就错了(因为依赖于实现细节),因为文档总是说BOOLtypes(C)对象的有效值是NOYES 。 期。

从2014年开始(?2013?), BOOLtypes变得更像C _Booltypes。 这意味着为该types的对象赋值> 1,将1( YES )存储到variables中。 所以,无论如何,行为改变了。 (一个未定义的行为成为一个定义的行为,行为与旧的未定义行为是不同的。)

但是你的问题看起来像只有Bit0被存储。 (偶数为0,奇数为1)这将是一个错误。 请告诉我们完整的代码。

但是,您可以使用_Bool而不是BOOL

尝试使用这个,

  BOOL isEnabled; if ( ( myString.length % 2 ) == 0 ) { //Is even isEnabled=FALSE; } else { //Is odd isEnabled=TRUE; }