将NSUInteger分配给BOOL概念性理解

时间:2015-08-13 07:41:40

标签: ios objective-c iphone cocoa-touch

我正在努力寻找BOOL概念的一个很好的答案。据我所知,零是假值,非零是真值。想到这一点,我将字符串长度分配给BOOL变量。现在,这适用于iOS> 6.在iOS 6上,我看到了奇怪的结果。对于具有奇数长度的字符串,isEnabled为turing True但对于长度均匀的字符串,isEnabled为turing False。

BOOL isEnabled = myString.length;

请帮我理解这一点。当然,现在我已经将表达式分配给BOOL变量,如下所示:

BOOL isEnabled = myString.length > 0;

确切代码:

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

PS:如上所述,myString的长度正在变化;来自' a'到了' ab'到了#abc'等

3 个答案:

答案 0 :(得分:4)

  

但是,我无法理解iOS 6的行为,只启用奇数按钮。 [...]我很想知道根本原因。

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

BOOL

的类型

不同的行为实际上与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的实现细节

还涉及另一个微妙的技术细节。您实际上是在设置enabled的{​​{1}}属性。

Apple喜欢使用节省空间的方案在其UI组件中存储标志。 UIBarButtonItem(在32位和64位架构上)总是使用至少一个字节,但只需要一位信息。因此他们使用bit fields来存储实际值。

摘自iOS SDK 8.4 BOOL(为清晰起见缩写):

UIBarButtonItem.h

魔术是@interface UIBarButtonItem : UIBarItem { struct { unsigned int enabled:1; } _barButtonItemFlags; } 结构中:1字段后面的enabled。这定义了宽度为1的位域。要将_barButtonItemFlags属性与此位字段连接,它们必须实现自定义访问器。以下是setter的示例:

enabled

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

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

编译器理解它必须使用参数2调用someBarButtonItem.enabled = 2; 方法。

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

2内部,该值被赋予宽度为1的setEnabled: .C标准表示当分配宽度更大的无符号整数时,其余的位只是被丢弃。结果是unsigned int只存储setEnabled:中参数的最低位。最低位是奇数上的一位,偶数位上是零。

结论

以上所有行为都在标准提供的语义范围内。没有涉及未定义的行为。这是一个不幸的事实,_barButtonItemFlags.enabled的预期行为与您在32位架构上的实际行为不同。

答案 1 :(得分:1)

在早期,BOOL被实现为整数类型。因此,使用这样的实现可以分配值> 1到它并阅读它。但这从一开始就是错误的(因为依赖于实现细节),因为文档总是说BOOL类型的(C)对象的有效值是NO和{{1 }}。周期。

从2014年开始(?2013?),YES类型变得更像C BOOL类型。这意味着分配值>对于该类型的对象,1(_Bool)存储在变量中。所以,无论如何行为都发生了变化。 (未定义的行为成为已定义的行为,行为与旧的未定义行为不同。)

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

但是,您可以使用YES代替_Bool

答案 2 :(得分:-2)

尝试使用它,

    BOOL isEnabled;

    if ( ( myString.length % 2 ) == 0 ) {

        //Is even

    isEnabled=FALSE;

    }
    else {

        //Is odd
    isEnabled=TRUE;

    }