A few months ago I wrote here about a generic approach to safely take incoming JSON and save values to Core Data object. The goals of that code were twofold:
- Provide a safe, generic alternative to Cocoa’s
-setValuesForKeysWithDictionary:for use with NSManagedObject and its subclasses
- Handle cases where JSON data didn’t match up with what the managed objects expected. Getting a string where you expect a numeric value, or vice versa, for example, or getting a string representation of a date when you want a real NSDate object.
The first item was the most important. It’s tempting to use
-setValuesForKeysWithDictionary: to transfer JSON to a model object in one step. The method runs through the dictionary and calls
-setValue:forKey: on the target object for every entry. It has a fatal flaw though, in that it doesn’t check to see if the target object actually has a key before trying to set it. Using this method when you don’t have absolute control over the dictionary contents is an invitation to unknown key exceptions and nasty app crashes.
Fixing this for managed objects was relatively easy because Core Data provides convenient Objective-C introspection methods. The general approach was:
- Get a list of the target object’s attributes
- For each attribute, see if the incoming dictionary has an entry. If so,
- Compare the incoming type to the expected type, and convert if necessary.
-setValue:forKey:with that key and its value.
And then just last week I had the thought, wouldn’t it be nice if this worked for any object, not just for managed objects?