我正在努力寻找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'等
答案 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);
这是您在不同设备上看到不同行为的原因的解释。但奇怪的事情从何而来呢?
还涉及另一个微妙的技术细节。您实际上是在设置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;
}