问题描述
我想为BOOL的概念寻找一个好的答案。据我所知,零是一个假值,非零是一个真值。认为这我将字符串长度分配到BOOL变量。现在,这适用于iOS> 6.在iOS 6我看到奇怪的结果。对于奇长度的字符串,isEnabled是turing True,但对于长度为偶数的字符串,isEnabled是turing False。
BOOL isEnabled = myString 。长度;
请帮助我理解这一点。当然,现在我已经将表达式赋值给BOOL变量,如下所示:
BOOL isEnabled = myString.length> 0;
确切代码:
- (void)textViewDidChange:(UITextView *)iTextView {
self.navigationItem.rightBarButtonItem.enabled = [[self.noteTextView.text trim] length];
}
PS:如前所述,myString的长度正在改变;从'a'到'ab'到'abc'等。
为了解释观察到的行为,有两个技术细节要解释: Objective-C的类型 BOOL
和UIKit的实现细节。
的类型BOOL 不同的行为实际上与iOS em>。 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
因此 BOOL
on 32位可以有0和255之间的任何值,而在64位它是编译器强制只有值0或1.你可以很容易地尝试这个在模拟器上运行以下行,设置为iPhone 4s(32位)或iPhone 6(64位)。
NSLog(@%d,(BOOL)2);
这是为什么您在不同设备上看到不同行为的解释。
UIBarButtonItem的实现细节
还有一个微妙的技术细节参与。您实际上正在设置 UIBarButtonItem
的启用
属性。
Apple喜欢使用空间节省方案在他们的UI组件中存储标志。 A BOOL
(在32位和64位体系结构上)将始终使用至少一个字节,但只需要一个位的信息。因此,他们使用存储实际值。
从iOS SDK 8.4摘录 UIBarButtonItem.h
(为清楚起见缩短):
@interface UIBarButtonItem:UIBarItem {
struct {
unsigned int enabled:1;
} _barButtonItemFlags;
}
神奇的是:1
在 _barButtonItemFlags
结构中的启用
字段后面。这定义了宽度为1的位字段。要将启用的
属性与此位字段连接,他们必须实现自定义访问器。下面是设置器的示例:
- (void)setEnabled:(BOOL)enabled {
_barButtonItemFlags.enabled =启用;
}
那么,当我们这样做时会发生什么:
someBarButtonItem.enabled = 2;
编译器知道它必须调用 setEnabled:
2
在64位架构上, 2
将转换为 _Bool
,其中标准说这必须导致值 1
。在32位系统上不是这样,在调用该方法之前,保留 2
的原始值。
setEnabled:
内部的值分配给宽度为1的 unsigned int
。C标准说,分配更大宽度的无符号整数,则剩余的比特被丢弃。结果是 setEnabled:
只是存储 _barButtonItemFlags.enabled
中参数的最低位。
结论
所有上述行为是在标准提供的语义。没有未定义的行为。这是一个不幸的事实, BOOL
的预期行为与实际在32位体系结构上有所不同。
I am trying to look for a good answer to the concept of BOOL. As I understand, a zero is a false value, and non-zero is a true value. Thinking this I assigned string length into a BOOL variable. Now, this works fine for iOS > 6. On iOS 6 I see strange results. For string with odd length, isEnabled is turing True but for strings with even length, isEnabled is turing False.
BOOL isEnabled = myString.length;
Please help me understand this. Of course, now I've been assigning expressions to BOOL variable like this:
BOOL isEnabled = myString.length > 0;
Exact code:
- (void)textViewDidChange:(UITextView *)iTextView {
self.navigationItem.rightBarButtonItem.enabled = [[self.noteTextView.text trim] length];
}
PS: As mentioned, myString is changing in length; from 'a' to 'ab' to 'abc' etc.
解决方案 To explain the observed behavior there are two technical details to explain: The type of Objective-C's BOOL
and implementation details of UIKit.
Type of BOOL
The differing behavior is actually not related to the iOS version but to the device's architecture. There's a difference on how the iOS SDK defines a BOOL for 32 versus 64 bit architectures. See this excerpt from objc.h
:
#if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__
typedef bool BOOL;
#else
typedef signed char BOOL;
#endif
So BOOL
on 32 bit can have any value between 0 and 255, while on 64 bit it is compiler enforced to only have the values 0 or 1. You can easily try this by running the following line on the simulator, set to iPhone 4s (32 bit) or iPhone 6 (64 bit).
NSLog(@"%d", (BOOL)2);
This is the explanation for why you see differing behavior on different devices. But where does the even-odd thing come from?
Implementation details of UIBarButtonItem
There's another subtle technical detail involved. You are actually setting the enabled
property of a UIBarButtonItem
.
Apple likes to use a space saving scheme to store flags in their UI components. A BOOL
(on both 32 and 64 bit architectures) would always use at least one byte, but only one bit of information is needed. So they are using bit fields to store the actual value.
Excerpt from iOS SDK 8.4 UIBarButtonItem.h
(shortened for clarity):
@interface UIBarButtonItem : UIBarItem {
struct {
unsigned int enabled:1;
} _barButtonItemFlags;
}
The magic is the :1
behind the enabled
field in the _barButtonItemFlags
struct. This defines the bit-field of width one. To connect the enabled
property with this bit-field, they have to implement custom accessors. Here's an example for the setter:
- (void)setEnabled:(BOOL)enabled {
_barButtonItemFlags.enabled = enabled;
}
So what happens when we're doing this:
someBarButtonItem.enabled = 2;
The compiler understands that it has to call the setEnabled:
method with an argument of 2.
On 64 bit architectures the 2
would be converted to _Bool
, where the standard says this has to result in a value of 1
. On 32 bit systems this is not the case, leaving the original value of 2
in place, before calling the method.
Inside of setEnabled:
the value is assigned to an unsigned int
of width 1. The C standard says that when assigning an unsigned integer of greater width the remaining bits are just dropped. The result is that setEnabled:
just stores the lowest bit of the argument in _barButtonItemFlags.enabled
. The lowest bit is one on odd numbers, zero on even numbers.
Conclusion
All of the above behavior is within the semantics provided by the standard. There is no undefined behavior involved. It's just an unfortunate fact that the expected behavior of BOOL
differs from what you actually get on 32 bit architectures.
这篇关于将NSUInteger分配给BOOL的概念理解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!
objc.h
: #if!defined OBJC_HIDE_64)&&& TARGET_OS_IPHONE&& __LP64__
typedef bool BOOL;
#else
typedef signed char BOOL;
#endif
因此 BOOL
on 32位可以有0和255之间的任何值,而在64位它是编译器强制只有值0或1.你可以很容易地尝试这个在模拟器上运行以下行,设置为iPhone 4s(32位)或iPhone 6(64位)。
NSLog(@%d,(BOOL)2);
这是为什么您在不同设备上看到不同行为的解释。
UIBarButtonItem的实现细节
还有一个微妙的技术细节参与。您实际上正在设置 UIBarButtonItem
的启用
属性。
Apple喜欢使用空间节省方案在他们的UI组件中存储标志。 A BOOL
(在32位和64位体系结构上)将始终使用至少一个字节,但只需要一个位的信息。因此,他们使用存储实际值。
从iOS SDK 8.4摘录 UIBarButtonItem.h
(为清楚起见缩短):
@interface UIBarButtonItem:UIBarItem {
struct {
unsigned int enabled:1;
} _barButtonItemFlags;
}
神奇的是:1
在 _barButtonItemFlags
结构中的启用
字段后面。这定义了宽度为1的位字段。要将启用的
属性与此位字段连接,他们必须实现自定义访问器。下面是设置器的示例:
- (void)setEnabled:(BOOL)enabled {
_barButtonItemFlags.enabled =启用;
}
那么,当我们这样做时会发生什么:
someBarButtonItem.enabled = 2;
编译器知道它必须调用 setEnabled:
2
在64位架构上, 2
将转换为 _Bool
,其中标准说这必须导致值 1
。在32位系统上不是这样,在调用该方法之前,保留 2
的原始值。
setEnabled:
内部的值分配给宽度为1的 unsigned int
。C标准说,分配更大宽度的无符号整数,则剩余的比特被丢弃。结果是 setEnabled:
只是存储 _barButtonItemFlags.enabled
中参数的最低位。
结论
所有上述行为是在标准提供的语义。没有未定义的行为。这是一个不幸的事实, BOOL
的预期行为与实际在32位体系结构上有所不同。
I am trying to look for a good answer to the concept of BOOL. As I understand, a zero is a false value, and non-zero is a true value. Thinking this I assigned string length into a BOOL variable. Now, this works fine for iOS > 6. On iOS 6 I see strange results. For string with odd length, isEnabled is turing True but for strings with even length, isEnabled is turing False.
BOOL isEnabled = myString.length;
Please help me understand this. Of course, now I've been assigning expressions to BOOL variable like this:
BOOL isEnabled = myString.length > 0;
Exact code:
- (void)textViewDidChange:(UITextView *)iTextView {
self.navigationItem.rightBarButtonItem.enabled = [[self.noteTextView.text trim] length];
}
PS: As mentioned, myString is changing in length; from 'a' to 'ab' to 'abc' etc.
To explain the observed behavior there are two technical details to explain: The type of Objective-C's BOOL
and implementation details of UIKit.
Type of BOOL
The differing behavior is actually not related to the iOS version but to the device's architecture. There's a difference on how the iOS SDK defines a BOOL for 32 versus 64 bit architectures. See this excerpt from objc.h
:
#if !defined(OBJC_HIDE_64) && TARGET_OS_IPHONE && __LP64__
typedef bool BOOL;
#else
typedef signed char BOOL;
#endif
So BOOL
on 32 bit can have any value between 0 and 255, while on 64 bit it is compiler enforced to only have the values 0 or 1. You can easily try this by running the following line on the simulator, set to iPhone 4s (32 bit) or iPhone 6 (64 bit).
NSLog(@"%d", (BOOL)2);
This is the explanation for why you see differing behavior on different devices. But where does the even-odd thing come from?
Implementation details of UIBarButtonItem
There's another subtle technical detail involved. You are actually setting the enabled
property of a UIBarButtonItem
.
Apple likes to use a space saving scheme to store flags in their UI components. A BOOL
(on both 32 and 64 bit architectures) would always use at least one byte, but only one bit of information is needed. So they are using bit fields to store the actual value.
Excerpt from iOS SDK 8.4 UIBarButtonItem.h
(shortened for clarity):
@interface UIBarButtonItem : UIBarItem {
struct {
unsigned int enabled:1;
} _barButtonItemFlags;
}
The magic is the :1
behind the enabled
field in the _barButtonItemFlags
struct. This defines the bit-field of width one. To connect the enabled
property with this bit-field, they have to implement custom accessors. Here's an example for the setter:
- (void)setEnabled:(BOOL)enabled {
_barButtonItemFlags.enabled = enabled;
}
So what happens when we're doing this:
someBarButtonItem.enabled = 2;
The compiler understands that it has to call the setEnabled:
method with an argument of 2.
On 64 bit architectures the 2
would be converted to _Bool
, where the standard says this has to result in a value of 1
. On 32 bit systems this is not the case, leaving the original value of 2
in place, before calling the method.
Inside of setEnabled:
the value is assigned to an unsigned int
of width 1. The C standard says that when assigning an unsigned integer of greater width the remaining bits are just dropped. The result is that setEnabled:
just stores the lowest bit of the argument in _barButtonItemFlags.enabled
. The lowest bit is one on odd numbers, zero on even numbers.
Conclusion
All of the above behavior is within the semantics provided by the standard. There is no undefined behavior involved. It's just an unfortunate fact that the expected behavior of BOOL
differs from what you actually get on 32 bit architectures.
这篇关于将NSUInteger分配给BOOL的概念理解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!