Original address: Apple Pear blog
Well, I dug a hole for myself yesterday, but I still had to fill it early and finish it early, so today I have this article:
ObjC BOOL type
Maybe someone told you that BOOL is signed char. That was the right answer in the past, but it’s not quite right now. Let me explain a little bit of the details.
What type is an ObjC BOOL?
My current version of Xcode is 9.3.1, and the BOOL definition looks like this (with some cuts) :
#if TARGET_OS_OSX || (TARGET_OS_IOS && ! __LP64__ && ! __ARM_ARCH_7K)
# define OBJC_BOOL_IS_BOOL 0
#else
# define OBJC_BOOL_IS_BOOL 1
#endif
#if OBJC_BOOL_IS_BOOL
typedef bool BOOL;
#else
# define OBJC_BOOL_IS_CHAR 1
typedef signed char BOOL;
#endif
Copy the code
As an iPhone developer (๐), a BOOL is actually a BOOL on a 64-bit device, and a BOOL is actually a signed char on a 32-bit device.
What is YES/NO?
So what are the values of YES and NO? Let’s look at the definition:
#if __has_feature(objc_bool)
#define YES __objc_yes
#define NO __objc_no
#else
#define YES ((BOOL)1)
#define NO ((BOOL)0)
#endif
Copy the code
__objc_yes and __objc_no are the values of __objc_yes and __objc_no, which can be found in LLVM documentation:
The compiler implicitly converts __objc_yes and __objc_no to (BOOL)1 and (BOOL)0. The keywords are used to disambiguate BOOL and integer literals.
Copy the code
__objc_yes and __objc_no are really (BOOL)1 and (BOOL)0, just to disambiguate BOOL and integer.
(BOOL)1 and (BOOL)0, which I think you can easily understand, are just forcing 1 and 0 into the actual type of BOOL.
So in order for the type to correspond correctly, you need to use YES/NO when setting a BOOL.
What is true/false?
The earliest C language did not have a bool type. In 2000, C99 introduced the _Bool reserved word and defined true and false in stdbool. The contents of stdbool. H can be seen here:
#define bool _Bool
#define true 1
#define false 0
Copy the code
This is just the standard C definition (C++ comes with bool and true and false). You can see that the values are defined, but there is no guarantee of their types, meaning that true/false can be applied to a variety of data types.
Some people also mention TRUE/FALSE as a macro definition. They are not part of a standard definition, but were used in place of TRUE/FALSE when there was no standard definition. In most cases, they are the same.
We can write a code to verify this:
BOOL a = TRUE;
a = true;
a = YES;
Copy the code
Using Xcode’s menu for preprocessing, expand the macro definition:
Then we can get the expanded result:
BOOL a = 1;
a = 1;
a = __objc_yes;
Copy the code
Why use YES/NO for BOOL instead of true/false?
You can see that ObjC defines its own BOOL type, and then defines the corresponding values YES/NO to use, and of course the first reason is to follow the standard.
On the other hand, since ObjC’s BOOL does not use the standard C definition, this definition may change in the future. It’s a very low probability, but that’s a change from signed char to bool, isn’t it? To avoid this risk, it is recommended to use YES/NO.
In some cases, a type mismatch can result in a warning, and YES/NO is typed to ensure that the type is correct, so it is recommended to use YES/NO.
Note the use of type BOOL
Because the BOOL type behaves differently on different devices, there are a few things to be aware of.
Don’t write “== YES” and “! = YES”
When a BOOL is a BOOL, there are only two values: true and false, but you can actually write “== YES” and “! = YES “. Let’s start with an example:
BOOL a = 2;
if (a) {
NSLog(@"a is YES");
} else {
NSLog(@"a is NO");
}
if (a == YES) {
NSLog(@"a == YES");
} else {
NSLog(@"a ! = YES");
}
Copy the code
On 64-bit devices we will get the result:
a is YES
a == YES
Copy the code
It looks all right, perfect!
But on 32-bit devices we’ll get the result:
a is YES a ! = YESCopy the code
Why is that? Because on 32-bit devices a BOOL is signed char. ObjC makes (a) true or false statements on numeric types if 0 is false and if non-0 is true, so we get a is YES. But I don’t have to tell you what the logic is for doing (a == YES) on numeric types. The code translates like this:
signed char a = 2;
if (a == (signed char)1) {
NSLog(@"a == YES");
} else {
NSLog(@"a ! = YES");
}
Copy the code
Of course we got an A! = YES.
Avoid forcing BOOL values greater than 8-bit
On 64-bit devices, this is not a problem with bool types, but it is with signed char types. Let’s start with the code:
int a = 256;
if (a) {
NSLog(@"a is YES");
} else {
NSLog(@"a is NO");
}
BOOL b = a;
if (b) {
NSLog(@"b is YES");
} else {
NSLog(@"b is NO");
}
Copy the code
Output results on 32-bit devices:
a is YES
b is NO
Copy the code
Isn’t it a bit magical? But the reason is surprisingly simple:
a
The binary value of is 00000000 00000000 00000001 00000000- convert
signed char
The type ofb
When the high level is lost b
The binary value of
So don’t do anything stupid like this. A more common example is a C function (which is quite intuitive) :
Bool isDifferent(int a, int b) {returna - b; } // Error: signed char isDifferent(int a, int b) {return a - b;
}
Copy the code
conclusion
Hopefully today’s introduction has given you a better understanding of ObjC’s BOOL types, so be careful not to bury big bugs in your code.