Objective-C中的YES / NO,TRUE / FALSE和true / false是否有区别?


154

确实是一个简单的问题;这些值之间是否有区别(BOOL和bool之间是否有区别)?一位同事提到他们在Objective-C中对不同的事物进行评估,但是当我查看各自.h文件中的typedef时,YES / TRUE / true都定义为,1而NO / FALSE / false都定义为0。真的有区别吗?


5
从实际的角度来看,没有区别。您可能可以采取各种技巧来证明两者之间的差异,但是通常您会流连于“未定义的行为”领域。
Hot Licks 2012年

Answers:


84

如果您将BOOL变量用作布尔值,则没有实际区别。C根据布尔表达式的计算结果是否为0或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语言痛苦的困扰。


100

我相信有之间的差异boolBOOL,看看这个网页为什么的解释:
http://iosdevelopertips.com/objective-c/of-bool-and-yes.html

因为BOOLunsigned char基本类型,所以类型变量BOOL可以包含YES和以外的其他值NO

考虑以下代码:

BOOL b = 42;

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

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

输出为:

b不是NO!
b不是YES!

对于大多数人来说,这是不必要的问题,但是如果您确实想要布尔值,最好使用bool。我应该补充:iOS SDK通常BOOL在其接口定义上使用,因此必须坚持使用BOOL


5
但是请注意,原始的C实现没有no bool,因此使用an intchar作为布尔值是一种传统,有时使用#define隐藏差异,有时则没有。实际上,我不确定即使当前的标准是否也需要bool以防止检查其内部结构的方式实施。
Hot Licks 2012年

1
虽然,第一个printf讲的是谎言。的值为bnot YES,它是“非零”,这是条件测试的结果。所以您应该拥有printf("b is not zero"),但不一定与相同YES。在这种情况下,b既是“非零”又是“不是”。
劳伦斯·多尔

谢谢劳伦斯,我已经按照这些原则进行了更新。
Dan J

确实,我没有在Xcode 8.2中获得第二个输出。我哪里失败了?
伊戈尔·基斯留克

1
@HotLicks在0(不是零)与false和true之间没有固有的差异。只要该值是逻辑布尔值,它就始终具有此接口,以保持二进制兼容性。当您使用看起来像布尔值的非布尔值时,问题就开始了,例如,c标准库应用程序入口函数,成功时main返回0,许多人最终将此0视为布尔值,而实际上是应用程序定义的枚举或用户定义的值,被调用者通常期望在异常终止时不为零。
德米特里(Dmitry)

52

我对此进行了详尽的测试。我的结果应该说明一切:

//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

3
[[NSObject] alloc] init]不等于TRUE或YES。因此,使用if([[NSObject] alloc] init] == TRUE)测试对象初始化将失败。实际上,对于任何定义非零值的语言,我从未感到满意。
DrFloyd13年

3
@SamuelRenkert我从未对使用an if或a中的非布尔值的语言感到不舒服while。像... while("guitar gently weeps")不应该工作...
Supuhstar

@SamuelRenkert也是2003年发现的Linux后门:if (user_id = ROOT_UID)
Supuhstar

14

您可能需要阅读此问题的答案。总之,在Objective-C中(来自objc.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

11

true和之间的主要区别(危险!)YES是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类型,并true通过JSON序列化转换为。其他任何类似@(expression1 && expression2)(even @(YES && YES))的表达式都是__NSCFNumber (int)类型,并1在JSON中转换为。

PS您可以简单地使用字符串值的布尔值

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

1

这里没有人提到过一个微妙的错误,我想我应该包括...更多是逻辑错误,而不是其他任何错误:

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

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

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


从本质上讲,这与DanJ的答案早于2年前,答案相同,但细节较少。
劳伦斯·多尔

@LawrenceDol我不知道,它提到YES只是#defined定义为1,不是该语言固有的,就像它可能是高级语言一样……有人可能从中获得价值……但是很好拖曳,跟你。
Grady Player

0

我认为他们在很多情况下都添加“是/否”,这更加不言自明。例如:

[button setHidden:YES];

听起来比

[button setHidden:TRUE];

2
我不同意; 他们对我读的都是一样的。但是,在外行用户的UI中,我认为“是/否”看起来更好。
劳伦斯·多尔

16
我也不同意。如果有的话,由于不遵守多年来在其他语言中使用的不成文的标准,因此阅读效果很差。IE是当您不遵守大量标准时发生的情况的主要示例。
FreeAsInBeer 2011年

1
对2个不准确的答案进行
半票表决,

-2

首先,让我们检查什么是对与错,以及首先赋予它们含义的含义。

我们可以在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”或“ left”的函数,并在忽略另一个选项的同时进行选择,或者选择一个“ false”的函数来选择“ true”。

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

(\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. ())

使用doThis和doThat为(\ 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,零/一,apple / orange。它的意义在于,无论做出什么选择,它仅是由做出选择的那种人引起的。因此,如果打印了“ LEFT”,我们知道选择器只能是正确的,并且基于此知识,我们可以指导进一步的决策。

所以总结一下

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');
})();

-7

否,是/否是引用TRUE / FALSE(1/0)的另一种方式

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.