NSNull handling for NSManagedObject properties values

Lucien picture Lucien · Feb 4, 2012 · Viewed 8.5k times · Source

I'm setting values for properties of my NSManagedObject, these values are coming from a NSDictionary properly serialized from a JSON file. My problem is, that, when some value is [NSNull null], I can't assign directly to the property:

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

this throws a NSInvalidArgumentException

"winnerID"; desired type = NSString; given type = NSNull; value = <null>;

I could easily check the value for [NSNull null] and assign nil instead:

fight.winnerID = [dict objectForKey:@"winner"] == [NSNull null] ? nil : [dict objectForKey:@"winner"];

But I think this is not elegant and gets messy with lots of properties to set.

Also, this gets harder when dealing with NSNumber properties:

fight.round = [NSNumber numberWithUnsignedInteger:[[dict valueForKey:@"round"] unsignedIntegerValue]]

The NSInvalidArgumentException is now:

[NSNull unsignedIntegerValue]: unrecognized selector sent to instance

In this case I have to treat [dict valueForKey:@"round"] before making an NSUInteger value of it. And the one line solution is gone.

I tried making a @try @catch block, but as soon as the first value is caught, it jumps the whole @try block and the next properties are ignored.

Is there a better way to handle [NSNull null] or perhaps make this entirely different but easier?

Answer

Lily Ballard picture Lily Ballard · Feb 4, 2012

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.