Created
August 29, 2012 00:33
-
-
Save wearhere/3505652 to your computer and use it in GitHub Desktop.
Boolean literals are only sometimes of type BOOL.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
- (void)testBooleanLiteralsAreOfTypeBool { | |
NSNumber *testBoolNumber = @YES; | |
const char *typeString = [testBoolNumber objCType]; | |
STAssertTrue('c' == *typeString, @"Boxed BOOL is of type %s, not of type 'c' (signed char, aka BOOL).", typeString); | |
} | |
- (void)testBoxedBooleanLiteralsAreOfTypeBool { | |
// Boxing works fine if a BOOL value is boxed directly... | |
BOOL testBool = YES; | |
NSNumber *testBoolNumber = @(testBool); | |
const char *typeString = [testBoolNumber objCType]; | |
STAssertTrue('c' == *typeString, @"Boxed BOOL is of type %s, not of type 'c' (signed char, aka BOOL).", typeString); | |
// "" | |
BOOL testBool2 = !testBool; | |
NSNumber *testBoolNumber2 = @(testBool2); | |
const char *typeString2 = [testBoolNumber2 objCType]; | |
STAssertTrue('c' == *typeString2, @"Boxed BOOL is of type %s, not of type 'c' (signed char, aka BOOL).", typeString2); | |
// "" | |
NSNumber *testBoolNumber3 = [self testBoxedBooleanLiteralsAreOfTypeBoolMethodBoxingABoolLArgument:testBool]; | |
const char *typeString3 = [testBoolNumber3 objCType]; | |
STAssertTrue('c' == *typeString3, @"Boxed BOOL is of type %s, not of type 'c' (signed char, aka BOOL).", typeString3); | |
// "" | |
NSNumber *testBoolNumber4 = @([testBoolNumber3 boolValue]); | |
const char *typeString4 = [testBoolNumber4 objCType]; | |
STAssertTrue('c' == *typeString4, @"Boxed BOOL is of type '%s', not of type 'c' (signed char, aka BOOL).", typeString4); | |
// .. but not if a "raw Boolean" is boxed. | |
// Note: YES is here typedef'd to __objc_yes. | |
NSNumber *testBoolNumber5 = @(YES); | |
const char *typeString5 = [testBoolNumber5 objCType]; | |
STAssertFalse('c' == *typeString5, @"This is not broken, as expected: Boxed BOOL is of type 'c' (signed char, aka BOOL), not of type 'i'."); | |
// ... ditto the result of a "boolean expression". | |
NSNumber *testBoolNumber6 = @(!testBool); | |
const char *typeString6 = [testBoolNumber6 objCType]; | |
STAssertFalse('c' == *typeString6, @"This is not broken, as expected: Boxed BOOL is of type 'c' (signed char, aka BOOL), not of type 'i'."); | |
// If we cast the failing cases to BOOLs prior to boxing, we're alright. | |
NSNumber *testBoolNumber7 = @((BOOL)YES); | |
const char *typeString7 = [testBoolNumber7 objCType]; | |
STAssertTrue('c' == *typeString7, @"Boxed BOOL is of type %s, not of type 'c' (signed char, aka BOOL).", typeString7); | |
NSNumber *testBoolNumber8 = @((BOOL)!testBool); | |
const char *typeString8 = [testBoolNumber8 objCType]; | |
STAssertTrue('c' == *typeString8, @"Boxed BOOL is of type %s, not of type 'c' (signed char, aka BOOL).", typeString8); | |
} | |
- (NSNumber *)testBoxedBooleanLiteralsAreOfTypeBoolMethodBoxingABoolLArgument:(BOOL)testBool { | |
return @(testBool); | |
} |
Full explanation: in cases 5 and 6, the NSNumbers
produced do not have objCType == 'c'
, but rather 'i'
. This implies that the compiler is generating +[NSNumber numberWithInt:]
from the literal syntax in cases 5 and 6, not +[NSNumber numberWithBOOL:]
like in the others.
This can be a problem if you're serializing these NSNumbers
into JSON, where (depending on your library, at least SBJSON, but likely the others -- they probably all rely upon -[NSNumber objCType]
to serialize numeric vs. Boolean values) the Boolean values will be represented by "1" or "0" instead of by "true" and "false".
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
NB: Error cases are indicated with
STAssertFalse
.