28

I'm using NSJSONSerialization dataWithJSONObject to serialize my classes to JSON. When it serializes a BOOL, it gives it the value 1 or 0 in the JSON string. I need this to be true or false instead. Is this possible to do generically?

Ashwini Shahapurkar
  • 6,586
  • 6
  • 26
  • 35
Rocky Pulley
  • 22,531
  • 20
  • 68
  • 106

6 Answers6

30

When I create [NSNumber numberWithBool:NO], the NSJSONSerialization returns the word "false" in the JSON string.

EDIT With the new shortcuts you can also use these handy guys:

@(YES) /   @(NO)
@(1)   /   @(0)
@YES   /   @NO
@1     /   @0

This way you can avoid something like looping through your values. I want the exact opposite behavior but have NSNumber objects. So I have to loop...

EDIT II

mbi pointed out in the comments that there is a difference between iOS versions. So here is an iOS9 test:

NSDictionary *data = @{
    @"a": @(YES),
    @"b": @YES,
    @"c": @(1),
    @"d": @1
};
NSLog(@"%@", [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:data options:0 error:nil] encoding:NSUTF8StringEncoding]);

2016-07-05 02:23:43.964 Test App[24581:6231996] {"a":true,"b":true,"c":1,"d":1}
Community
  • 1
  • 1
Julian F. Weinert
  • 7,474
  • 7
  • 59
  • 107
  • 5
    There is a little caveat between iOS versions here! This code `[NSJSONSerialization dataWithJSONObject:@{ @"Test1" : @YES, @"Test2" : @(YES), @"Test3" : @true, @"Test4" : @(true) } options:nil error:nil]` produces this json on iOS 9 `{"Test4":true,"Test3":true,"Test2":true,"Test1":true}` but produces this json on iOS 8 and below `{"Test4":1,"Test3":1,"Test2":true,"Test1":true}` – mbi May 09 '16 at 14:59
  • Interesting... Thanks for this observation! – Julian F. Weinert May 09 '16 at 16:07
  • No, I didnt see that. I will delete my comment. Thanks for pointing out! – Helge Becker Apr 25 '17 at 12:38
15

Just ran across this myself, not sure if this is the best answer but...

Make sure to use @YES or @NO, then your outputted json will have true / false in it:

[NSJSONSerialization dataWithJSONObject:@{@"test": @YES} options:0 error: nil];

So you will have to turn your other "booleans" / boolean like values -> @YES / @NO when putting into the dictionary for dataWithJSONObject.

[NSJSONSerialization dataWithJSONObject:@{@"test": (boolLikeValue ? @YES : @NO)} options:0 error: nil];
jaredpetker
  • 560
  • 5
  • 8
  • I find this helpful since not always one can use literals directly. e.g. In a function receiving a `BOOL` parameter, you'll need to convert the primitive `BOOL` to one of the acknowledgeable `@BOOL` literals` @YES` and `@NO` – Motti Shneor Sep 16 '19 at 07:53
5

Yes, it is possible to output a boolean (true/false) with NSJSONSerialization by using kCFBooleanTrue and kCFBooleanFalse :

NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:kCFBooleanTrue, @"key_1",
                           kCFBooleanFalse, @"key_2",
                           nil]  

then

NSError *error = nil;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:kNilOptions error:&error];
Olivier
  • 51
  • 1
  • 2
3

No, the Foundation Object for a Bool is NSNumber numberWithBool, which becomes either 0 or 1. We have no Bool Object. Same go for reading JSON. True/false will become a NSNumber again.

You could create an Bool Class and build your own parser. Arrays are Arrays and JSON Objects are NSDictionary. You can query the keys, test what Class lies behind and build the JSON String from this.

leopic
  • 2,958
  • 2
  • 27
  • 42
Helge Becker
  • 3,219
  • 1
  • 20
  • 33
1

I ran into similar issue when using CoreData's boolean, which is stored as NSNumber too. The easiest solution for me was using @():

[NSJSONSerialization dataWithJSONObject:@{@"bool": @([object.value boolValue])} options:0 error: nil];

I guess @() does recognize the BOOL value and initialize the NSNumber with numberWithBool: which leads to true/false in JSON

JakubKnejzlik
  • 6,363
  • 3
  • 40
  • 41
1

I just hit the issue on iOS9. My case is that I have a CoreData property workout.private which is bool mapped to NSNumber* due to CoreData handling.

When creating JSON [NSNumber numberWithBool:workout.private.boolValue] sets expected true/false in JSON, but just workout.private or @(workout.private.boolValue) sets "1" or "0".

mixtly87
  • 1,675
  • 15
  • 32