在目标-c 中,YES/NO、 TRUE/FALSE 和 TRUE/FALSE 之间有区别吗?

真的很简单的问题; 这些值之间有区别吗(BOOL 和 BOOL 之间有区别吗) ?一个同事提到他们在 Objective-C 中对不同的事情进行评估,但是当我查看他们各自的 typedef 时。H 文件,YES/TRUE/TRUE 全部定义为 1,NO/FALSE/FALSE 全部定义为 0。真的有区别吗?

104001 次浏览

NO,YES/NO 是指 TRUE/FALSE (1/0)的另一种方式

使用 BOOL变量作为布尔值并没有实际的区别。C 根据布尔表达式的值是否为0来处理布尔表达式。所以:

if(someVar ) { ... }
if(!someVar) { ... }

意思与

if(someVar!=0) { ... }
if(someVar==0) { ... }

这就是为什么可以将任何基本类型或表达式作为布尔测试(包括指针)来计算的原因。请注意,您应该做前者,而不是后者。

注意,如果将钝值赋给所谓的 BOOL变量并测试特定的值,那么 会有所不同,因此始终将它们作为布尔值使用,并且只从它们的 #define值中赋值。

重要的是,永远不要使用字符比较来测试布尔值——这不仅有风险,因为 someVar可能会被赋予一个非零值,而这个值不是 YES,而且,在我看来,更重要的是,它无法正确地表达意图:

if(someVar==YES) { ... } // don't do this!
if(someVar==NO ) { ... } // don't do this either!

换句话说,按照它们的意图和文档来使用构造,这样您就可以避免在 C 语言中受到伤害。

我认为在许多情况下,他们加上“是”或“否”是为了更好地解释。例如:

[button setHidden:YES];

听起来比

[button setHidden:TRUE];

您可能需要阅读这个 有个问题的答案。总之,在 Objective-C 中(来自 objecc.h 中的定义) :

typedef signed char        BOOL;
// BOOL is explicitly signed so @encode(BOOL) == "c" rather than "C"
// even if -funsigned-char is used.
#define OBJC_BOOL_DEFINED




#define YES             (BOOL)1
#define NO              (BOOL)0

我相信 boolBOOL之间是有区别的,看看这个网页可以解释为什么:
Http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

因为 BOOLunsigned char而不是基元类型,所以 BOOL类型的变量可以包含 YESNO以外的值。

考虑下面的代码:

BOOL b = 42;


if (b) {
printf("b is not NO!\n");
}


if (b != YES) {
printf("b is not YES!\n");
}

输出结果是:

B 不是 NO!
B 不是“是”!

对于大多数人来说,这是一个不必要的担心,但是如果您真的想要一个布尔值,那么最好使用 bool。我应该补充一点: iOS SDK 通常在其接口定义上使用 BOOL,因此这是一个与 BOOL相关的参数。

我对此做了一个详尽的测试,我的结果可以说明一切:

//These will all print "1"
NSLog(@"%d", true == true);
NSLog(@"%d", TRUE == true);
NSLog(@"%d", YES  == true);
NSLog(@"%d", true == TRUE);
NSLog(@"%d", TRUE == TRUE);
NSLog(@"%d", YES  == TRUE);
NSLog(@"%d", true == YES);
NSLog(@"%d", TRUE == YES);
NSLog(@"%d", YES  == YES);


NSLog(@"%d", false == false);
NSLog(@"%d", FALSE == false);
NSLog(@"%d", NO    == false);
NSLog(@"%d", false == FALSE);
NSLog(@"%d", FALSE == FALSE);
NSLog(@"%d", NO    == FALSE);
NSLog(@"%d", false == NO);
NSLog(@"%d", FALSE == NO);
NSLog(@"%d", NO    == NO);




//These will all print "0"
NSLog(@"%d", false == true);
NSLog(@"%d", FALSE == true);
NSLog(@"%d", NO    == true);
NSLog(@"%d", false == TRUE);
NSLog(@"%d", FALSE == TRUE);
NSLog(@"%d", NO    == TRUE);
NSLog(@"%d", false == YES);
NSLog(@"%d", FALSE == YES);
NSLog(@"%d", NO    == YES);


NSLog(@"%d", true == false);
NSLog(@"%d", TRUE == false);
NSLog(@"%d", YES  == false);
NSLog(@"%d", true == FALSE);
NSLog(@"%d", TRUE == FALSE);
NSLog(@"%d", YES  == FALSE);
NSLog(@"%d", true == NO);
NSLog(@"%d", TRUE == NO);
NSLog(@"%d", YES  == NO);

输出结果是:

2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.061 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.072 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.073 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.074 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.075 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.076 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.077 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.078 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.079 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.080 BooleanTests[27433:a0f] 1
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.081 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.082 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.091 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.092 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.093 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.094 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.095 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.096 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.097 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.098 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.101 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0
2013-02-19 20:30:37.102 BooleanTests[27433:a0f] 0

这里有一个微妙的错误,没有人提到过,我认为我会包括... 更多的逻辑错误比任何东西:

int i = 2;
if(i);        //true
if(i==YES);   // false
if((!!i)==YES); //true

所以这里的问题是 (YES==1)和 C 中的比较不是布尔型的,而是基于值的。

因为 YES只是一个 #define(而不是语言固有的东西) ,它必须有一些价值,而 1是最有意义的。

trueYES之间的主要(危险!)区别在于 JSON 序列化。

例如,我们有 JSON 类型的服务器请求,并且需要在 json 语句中发送 true/false:

NSDictionary *r1 = @{@"bool" : @(true)};
NSDictionary *r2 = @{@"bool" : @(YES)};
NSDictionary *r3 = @{@"bool" : @((BOOL)true)};

然后,我们将其转换为 JSON 字符串,然后将其发送为

NSData *data = [NSJSONSerialization  dataWithJSONObject:requestParams options:0 error:nil];
NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];

结果就是

jsonString1 // {"bool":1}
jsonString2 // {"bool":true}
jsonString3 // {"bool":true}

由于 API 逻辑 jsonString1可能导致错误。

所以在 Objective-C 中要小心布尔型。

总而言之,只有确切的 @YES和类似于 @((BOOL)expression)的强制转换值是 __NSCFBoolean类型的,并且通过 JSON 序列化转换为 true。 任何其他表达式,如 @(expression1 && expression2)(甚至是 @(YES && YES))都是 __NSCFNumber (int)类型的,并在 JSON 中转换为 1

另外,您可以简单地使用字符串值布尔值

@{@"bool" : @"true"}; // in JSON {"bool":true}

首先,让我们来分析一下什么是真,什么是假,以及是什么首先赋予了它们意义。

我们可以在 lambda 演算中构造一个叫做 if a then b else c 的结构,如下所示:

(\ifThenElse. <use if then else>)(\a. \b. \c. a b c)

在 JavaScript 中,如下所示:

(function(ifThenElse) {
// use ifThenElse
})(function(a) {
return function(b) {
return function(c) {
return a(b)(c);
};
};
});

为了使 ifThenElse 有用,我们需要一个选择向右或向左的函数“ true”,并且忽略另一个选项,或者一个选择选项“ true”的函数“ false”不接受这个选项。

我们可以将这些职能定义如下:

(\true. <use true>)(\a. \b. a) and (\false. <use false>)(\a. \b. b)

在 JavaScript 中看起来是这样的:

(function(True) {
// use True
})(function(a) {
return function(b) {
return a;
}
});


(function(False) {
// use True
})(function(a) {
return function(b) {
return b;
}
});

现在我们可以做以下事情

(\true. \false. \ifThenElse. \doThis. \doThat. ifThenElse true doThis doThat)
(\a. \b. a)(\a. \b. b)(\a. \b. \c. a b c)(\a. ())(\a. ())

因为 lambda 微积分不提供任何服务,比如打印/数学/字符串,我们所能做的就是什么都不做,说我们做了(然后用我们系统中提供我们想要的副作用的服务替换它)

让我们看看它的实际效果。

(function(True) {
return (function(False) {
return (function(ifThenElse) {
return (function(doThis) {
return (function(doThat) {
return ifThenElse(True)(doThis)(doThat);
});
});
});
})
})(function(a) {
return function(b) {
return a;
}
})(function(a) {
return function(b) {
return b;
}
})(function(a) {
return function(b) {
return function(c) {
return a(b)(c);
};
};
})(function(a) { console.log("you chose LEFT!"); })
(function(a) {console.log("you chose RIGHT");})();

如果允许我们使用数组/地图/参数/或者多个语句来分解成多个函数,这是一个可以简化的深层环境,但是我想保持尽可能纯粹,我只限制自己使用一个参数的函数。

请注意,True/False 这个名称没有固有的意义,我们可以很容易地将它们重命名为 yes/no、 left/right、 right/left、 zero/one、 apple/Orange。它的意义在于,无论做出什么样的选择,都是由选择者所做出的那种选择造成的。因此,如果“左”被打印,我们知道选择者只可能是真实的,基于这个知识,我们可以指导我们进一步的决定。

总结一下

function ChooseRight(left) {
return function _ChooseRight_inner(right) {
return right;
}
}
function ChooseLeft(left) {
return function _ChooseLeft_inner(right) {
return left;
}
}


var env = {
'0': ChooseLeft,
'1': ChooseRight,
'false': ChooseRight,
'true': ChooseLeft,
'no': ChooseRight
'yes': ChooseLeft,
'snd': ChooseRight,
'fst': ChooseLeft
};
var _0 = env['0'];
var _1 = env['1'];
var _true = env['true'];
var _false = env['false'];
var yes = env['yes'];
var no = env['no'];


// encodes church zero or one to boolean
function lambda_encodeBoolean(self) {
return self(false)(true);
}
// decodes a Boolean to church zero or one
function lambda_decodeBoolean(self) {
console.log(self, self ? env['true'] : env['false']);
return self ? env['true'] : env['false'];
}


lambda_decodeBoolean('one' === 'two')(function() {
console.log('one is two');
})(function() {
console.log('one is not two');
})();


lambda_decodeBoolean('one' === 'one')(function() {
console.log('one is one');
})(function() {
console.log('one is not one');
})();