BOOL,你真的了解吗?

2016-05-22

BOOL对于我们来说,再熟悉不过了,但是,你真的会用BOOL吗?哈哈,没别的意思,只是想说明BOOL其实还有点坑。也许你拥有多年的开发经验,有可能在开发中会因BOOL导致错误。哈哈,有可能你现在在想,BOOL 不就是 真(1)与假(0)的区别嘛,会有什么坑呢?或者 你会想,我是不是在乱说呢?。不要着急,请听我细细说来。希望我下面的介绍会给你带来启示。


BOOL & bool

我们都知道 BOOL 被定义在 Objective-C中(注意,在64-bitiOS设备或者模拟器上已经把BOOL定义成了bool,因此以下我们考虑其他平台,包括运行实例)。bool这种类型的布尔,出现在古老的C语言中。但是BOOL实际上是一种对带符号类型(signed char)的类型定义,它拥有 8 bits的存储空间。通过#define指令把YES定义为1NO定义为0Objective-C并不会将BOOL作为仅能保存YESNO值的真正布尔类型来处理。编译器仍将BOOL看作为8 bits二进制数。YESNO值只是在习惯上的一种理解,同时也是为了与C语言中的falsetrue区别与一致。
Objective-C中是这样定义的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#if (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH
#define OBJC_BOOL_IS_BOOL 1
typedef bool BOOL;// 在64-bite下的iPhone,被定义成 bool
#else
#define OBJC_BOOL_IS_CHAR 1
typedef signed char BOOL;//定义 成 char类型
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C"
// even if -funsigned-char is used.
#endif

#if __has_feature(objc_bool)
#define YES __objc_yes
#define NO __objc_no
#else
#define YES ((BOOL)1)
#define NO ((BOOL)0)
#endif


bool就两个值0非0,其实是一种(int)整型,即0代表false,非0代表为true.简单的描述下应该是这样定义:

1
2
3
4
5
6
7
8

#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif

具体定义请谷歌一下。也许有人说bool应该是01.请不用纠结这个问题,这个问题源于c语言的版本问题。在C语言标准(C98)并没有定义布尔类型,所以判断真假以0为假,非0为真,而在C99中,解决了布尔类型的问题。_Bool(bool)变量只能赋值为01.非0的值都被存储为1.即true代表1false代表0。请参考C99头文件<stdbool.h>bool的定义。
因此Objective-C中的BOOLC语言中bool是不同的。最大的区别就是两种定义的类型完全不同,一种使char,一种是int
比如说我可以这样对BOOLbool赋值

1
2
3
4
5
6

BOOL isValue1 = 8960;//256
bool isValue2 = 8960;//256

printf("value1 = %d,value2 = %d\n",isValue1,isValue2);

你认为会得到怎样的结果呢?
输出结果是:value1 = 0,value2 = 1
为什么会这样呢?请继续往下看…


BOOL–不要与YES作比较

YESObjective-C的真值,与值1相等。BOOL能够拥有从-128127(包括零)任意一个零值,因此它代表了255种不同的真值。按照惯例,那些函数或者方法总是返回YES或者NO。但是,你不能依赖于它返回的是真值(255种值的任意一个),就说明与YES(它的值为1)就相等。因此与YES(1)想比较是一种不好的想法。像这样:

1
2
3
4
if ([obj1 has:obj2] == YES) {
//code
}

因为没有编译器会执行一个变量或者一个值,总是保持YES或者NO
也许,你还不是很明白,没关系,我再举一个例子说明,直接与YES比较是不合理的。

1
2
3
4
5

static BOOL compareDifferent(int value1,int value2) {
return value1 - value2;
}

或者

1
2
3
4
5

- (BOOL)compareDifferenValue:(int)v1 value2:(int)v2 {
return v1 - v2 ;
}

然而,你像这样使用方法或者函数,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	
if (compareDifferent(25,24) == YES) {
printf("不相等\n");
}else {
printf(“相等\n”);
}

if (compareDifferent(24,25) == YES) {
printf("不相等\n");
}else {
printf(“相等\n”);
}

if (compareDifferent(15,45) == YES) {
printf("不相等\n");
}else {
printf(“相等\n”);
}

if (compareDifferent(512,256) == YES) {
printf("不相等\n");
}else {
printf("相等\n");
}

以上实例,你觉得会得到什么结果呢?会输出 “不相等”吗?。哈哈…,不好意思,编译器会给你开一个玩笑!,最终输出的结果会是这样的

1
2
3
4
5
6
7


不相等
相等
相等
相等

实际上返回值应该是1-1-30,0。注意最后一个输出为什么是0。当然,与NO相比较,总是安全的,因为在C语言中只有0代表false,在OC也一样 YESNO

我们来分析下,512256相比较为什么是相等,即返回值是0。有这样一段代码:

1
2
3
4

BOOL trueOrFalse = (BOOL)256;
printf("->%d\n",trueOrFalse);

输出结果是0NO。我们把256转化成二进制位1 0000 0000。根据BOOL,是一个占8 bitschar类型。因此编译器会剔除高位的数据,保留低8位的数据。在这个1 0000 0000中,保留0000 0000,再转化成10进制为00OC中被定义为NO。而 512 - 256 等于 256。因此会输出相等。我们把上面的代码片段 修改成这样:

1
2
3
4
5

bool trueOrFalse = (bool)256;

printf("->%d\n",trueOrFalse);

输出结果是1YES。因为 bool 就两个值01
再举一个例子。

1
2
3
4
5
6
7

NSString *name = @"test";

BOOL haveName() {
return (BOOL)name;
}

这种 返回的 结果是不确定的,有可能是YES,也有可能是NO。假设name的指针是0x010CA683,将返回YES,如果name指针是0x010BA600,将返回NO
原因也是BOOL类型只会保留8 bits 的数据。为真的时候保留0x83,为假的时候保留0x00。因此你可以这样做:

1
2
3
4
5
6
7

if (name) {
return YES;
}else {
retrun NO;
}

或者

1
2
3

retrun name !=nil ? YES : NO;

因此,不要这样写是非常有必要的,千万不要这样写:

1
2
3
4
5
6
7
8

// Never do this
if (someValue == YES ) {
//code
}else {
//code
}

或者

1
2
3
4
5
6
7
8

//Never do this
if (someValue == true ) {
//code
}else {
//code
}

但可以这样写

1
2
3

//代码规范不推荐这样写
if (someValue == NO) {}
1
2
3

//代码规范推荐这样写
if (!someValue) {}

!!注意:以上实例可以建立一个 MAC工程,运行,观测其输出结果。!!


总结

非常感谢你能看完本文文章,所以在使用YES与其他相比较的时候特别的注意,这也是在代码规范中特别要避免的地方。如上面有什么错误,请联系我`woodjobber@outlook.com`。非常感谢!!!

微信公众号:嘀咕嘀咕(iOSSharers)

扫二维码关注