NSNull handling for NSManagedObject properties values NSNull handling for NSManagedObject properties values objective-c objective-c

NSNull handling for NSManagedObject properties values


It might be a little easier if you wrap this in a macro:

#define NULL_TO_NIL(obj) ({ __typeof__ (obj) __obj = (obj); __obj == [NSNull null] ? nil : obj; })

Then you can write things like

fight.winnerID = NULL_TO_NIL([dict objectForKey:@"winner"]);

Alternatively you can pre-process your dictionary and replace all NSNulls with nil before even trying to stuff it into your managed object.


Ok, I've just woke up this morning with a good solution. What about this:

Serialize the JSON using the option to receive Mutable Arrays and Dictionaries:

NSMutableDictionary *rootDict = [NSJSONSerialization JSONObjectWithData:_receivedData options:NSJSONReadingMutableContainers error:&error];...

Get a set of keys that have [NSNull null] values from the leafDict:

NSSet *nullSet = [leafDict keysOfEntriesWithOptions:NSEnumerationConcurrent passingTest:^BOOL(id key, id obj, BOOL *stop) {    return [obj isEqual:[NSNull null]] ? YES : NO;}];

Remove the filtered properties from your Mutable leafDict:

[leafDict removeObjectsForKeys:[nullSet allObjects]];

Now when you call fight.winnerID = [dict objectForKey:@"winner"]; winnerID is automatically going to be (null) or nil as opposed to <null> or [NSNull null].

Not relative to this, but I also noticed that it is better to use a NSNumberFormatter when parsing strings to NSNumber, the way I was doing was getting integerValue from a nil string, this gives me an undesired NSNumber of 0, when I actually wanted it to be nil.

Before:

// when [leafDict valueForKey:@"round"] == nilfight.round = [NSNumber numberWithInteger:[[leafDict valueForKey:@"round"] integerValue]]// Result: fight.round = 0

After:

__autoreleasing NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];fight.round = [numberFormatter numberFromString:[leafDict valueForKey:@"round"]];    // Result: fight.round = nil


I wrote a couple of category methods to strip nulls from a JSON-generated dictionary or array prior to use:

@implementation NSMutableArray (StripNulls)- (void)stripNullValues{    for (int i = [self count] - 1; i >= 0; i--)    {        id value = [self objectAtIndex:i];        if (value == [NSNull null])        {            [self removeObjectAtIndex:i];        }        else if ([value isKindOfClass:[NSArray class]] ||                 [value isKindOfClass:[NSDictionary class]])        {            if (![value respondsToSelector:@selector(setObject:forKey:)] &&                ![value respondsToSelector:@selector(addObject:)])            {                value = [value mutableCopy];                [self replaceObjectAtIndex:i withObject:value];            }            [value stripNullValues];        }    }}@end@implementation NSMutableDictionary (StripNulls)- (void)stripNullValues{    for (NSString *key in [self allKeys])    {        id value = [self objectForKey:key];        if (value == [NSNull null])        {            [self removeObjectForKey:key];        }        else if ([value isKindOfClass:[NSArray class]] ||                 [value isKindOfClass:[NSDictionary class]])        {            if (![value respondsToSelector:@selector(setObject:forKey:)] &&                ![value respondsToSelector:@selector(addObject:)])            {                value = [value mutableCopy];                [self setObject:value forKey:key];            }            [value stripNullValues];        }    }}@end

It would be nice if the standard JSON parsing libs had this behaviour by default - it's almost always preferable to omit null objects than to include them as NSNulls.