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:

  • aThe binary value of is 00000000 00000000 00000001 00000000
  • convertsigned charThe type ofbWhen the high level is lost
  • bThe 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.