TouchJSON, dealing with NSNull

2019-01-06 17:23发布

问题:

Hi I am using TouchJSON to deserialize some JSON. I have been using it in the past and on those occasions I dealt with occurrences of NSNull manually. I would think the author had to deal with this as well, so me doing that again would just be overhead. I then found this in the documentation:

Avoiding NSNull values in output.

NSData *theJSONData = /* some JSON data */
CJSONDeserializer *theDeserializer = [CJSONDeserializer deserializer];
theDeserializer.nullObject = NULL;
NSError *theError = nil;
id theObject = [theDeserializer deserialize:theJSONData error:&theError];}

The way I understand it the user of the class can pass a C-style null pointer to the deserializer and when it encounters a NSNull it will insert the values (NULL) passed to it. So later on when I use the values I won't get NSNull, but NULL.

This seems strange, the return value is an NSDictionary which can only contain Objects, shouldn't the value default to 'nil' instead?

If it is NULL can I check the values like this?

if([jsonDataDict objectForKey:someKey] == NULL)

It would seem more logically to be able to do this:

if(![jsonDataDict objectForKey:someKey])

No to mention all the cases where passing nil is allowed but passing NULL causes a crash.

Or can I just pass 'nil' to the deserializer?

Much of this stems from me still struggling with nil, NULL, [NSNULL null], maybe I am failing to see the potential caveats in using nil.

回答1:

nil and NULL are actually both equal to zero, so they are, in practice, interchangeable. But you're right, for consistency, the documentation for TouchJSON should have used theDeserializer.nullObject = nil instead of NULL.

Now, when you do that, your second predicate actually works fine:

if (![jsonDataDict objectForKey:someKey])

because TouchJSON omits the key from the dictionary when you have nullObject set to nil (or NULL). When the key doesn't exist in the dictionary, NSDictionary returns nil, which is zero so your if condition works as you expect.

If you don't specify nullObject as nil, you can instead check for null like so:

if ([jsonDataDict objectForKey:someKey] == [NSNull null])


回答2:

For another JSON library, but with the same issues, I've created the following category on NSDictionary:

@implementation NSDictionary (Utility)

// in case of [NSNull null] values a nil is returned ...
- (id)objectForKeyNotNull:(id)key {
   id object = [self objectForKey:key];
   if (object == [NSNull null])
      return nil;

   return object;
}

@end

Whenever I deal with JSON data from said library, I retrieve values like this:

NSString *someString = [jsonDictionary objectForKeyNotNull:@"SomeString"];

This way the code in my projects become a lot cleaner and at the same time I don't have to think about dealing with [NSNull null] values and the like.



回答3:

There are libraries which deal with it. One of them is SwiftyJSON in Swift, another one is NSTEasyJSON in Objective-C. With this library (NSTEasyJSON) it will be easy to deal with such problems. In your case you can just check values you need:

NSTEasyJSON *JSON = [NSTEasyJSON withData:JSONData];
NSString *someValue = JSON[someKey].string;

This value will be NSString or nil and you should not check it for NSNull, NULL yourself.