0

When I try to convert NSMutableDictionary to JSON with NSJSONSerialization it returns different results:

Code:

-(NSString*)JSONRepresentation{

    return [self JSONRepresentation:NO];
}

-(NSString*)JSONRepresentation:(BOOL)whiteSpaces{

    NSError* error = nil;
    NSData * result = nil;

    if(whiteSpaces)
        result = [NSJSONSerialization dataWithJSONObject:self options:NSJSONWritingPrettyPrinted error:&error];
    else
        result = [NSJSONSerialization dataWithJSONObject:self options:kNilOptions error:&error];

    if (error != nil){
        NSLog(@"Error:%@",error);
        return nil;
    }

    return [NSString stringWithUTF8String:[result bytes]];
}

This is how I use it:

NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:@"xxx" forKey:@"experiment"];

NSLog(@"(%@)", [dict JSONRepresentation]);

Results in consecutive tries:

2013-08-01 12:31:45.066 Hercules Demo[8763:c07] ((null))
2013-08-01 12:31:49.988 Hercules Demo[8763:c07] ((null))
2013-08-01 12:31:52.838 Hercules Demo[8763:c07] ({"experiment":"xxx"})
2013-08-01 12:31:59.432 Hercules Demo[8763:c07] ({"experiment":"xxx"})
2013-08-01 12:32:03.160 Hercules Demo[8763:c07] ((null))
2013-08-01 12:32:06.232 Hercules Demo[8763:c07] ({"experiment":"xxx"})
2013-08-01 12:32:08.395 Hercules Demo[8763:c07] ((null))
Cyprian
  • 9,423
  • 4
  • 39
  • 73
  • 1
    Have you also logged the object you're converting to JSON? – Hot Licks Aug 01 '13 at 20:12
  • Also, you are continuing the serialization after the validation fails. – Mike D Aug 01 '13 at 20:14
  • 3
    Also, show us the code for `JSONRepresentation`. Above you show the code for `JSONRepresentation:`, which is entirely different. – Hot Licks Aug 01 '13 at 20:15
  • Yes, what if you call `JSONRepresentation:NO` instead? – Nicholas Hart Aug 01 '13 at 20:17
  • 1
    While Hot Licks is undoubtedly right, as an aside, I'd also be inclined to (a) define `result` as a `NSData` (because that's what `dataWithJSONObject` returns); and (b) use `[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]` rather than than `[NSString stringWithUTF8String:[result bytes]]`. – Rob Aug 01 '13 at 21:28
  • @HotLicks Yes I logged the NSMutableDictionary and it exists every time. Even converting results from id to NSData does not change anything as well as running JSONRepresentation: set to YES or NO. – Cyprian Aug 01 '13 at 22:10
  • @Rob What did work was your second comment about changing [NSString stringWithUTF8String:[result bytes]] to [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding]. Please add this as an unswer so I can approve it. Thank you – Cyprian Aug 01 '13 at 22:11
  • That is peculiar. `[result bytes]` is a temp that goes poof when `result` does, but one wouldn't expect that to happen until the method ends. It sounds like there's a "feature" of ARC that releases `result` immediately after the last reference, which would be before `bytes` is passed to the NSString `init` routine. It would be interesting to insert a dummy reference to `result` after the string is created and see if that makes the original code behave. – Hot Licks Aug 01 '13 at 23:09
  • @HotLicks I didn't suggest `initWithData` for memory semantics, but rather because the `NSData` doesn't include a `NULL` termination character that `stringWithUTF8String` requires. The next byte could, by happenstance, be `NULL`, but you have no assurances of that, AFAIK. – Rob Aug 01 '13 at 23:47
  • @Rob - Good point. If that's the problem then `initWithBytes:length:encoding:` should work. Though `initWithData` is definitely better. (However, the lack of null termination shouldn't cause the given symptoms. Eventually a zero byte would occur in the "garbage", or a storage error would occur.) – Hot Licks Aug 02 '13 at 00:15

1 Answers1

1

The dataWithJSONObject method returns a NSData, so I'd suggest:

  1. To convert a NSData into a NSString, you should use initWithData rather than stringWithUTF8String. So, rather than:

    return [NSString stringWithUTF8String:[result bytes]];
    

    You should do:

    return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
    
  2. For the sake of clarity, you probably should define result to be a NSData * rather than id.

Rob
  • 415,655
  • 72
  • 787
  • 1,044