views:

51

answers:

2

Hi

I parse some JSON from a web service, this gives me an NSDictionary, I use this dictionary to populated properties on a valueEntity of type NSObject by

[myObject setValuesForKeysWithDictionary:JSONDict];

(myObject has the same property names and types as the dictionary from the JSON parser)

name = name
count = count
startDate = startDate
etc..

Is there a way to go the other way, where I have an NSDictionary that I would like to have "filled" with the properties and their values from an my NSObject subclass. Like I suggest in the title, something along the lines of this:

one way

MyObject *myObject = [[MyObject alloc] init];
[myObject setValuesForKeysWithDictionary:JSONDict];

the other way around

NSMutableDictionary *dict = [myObject makeDictionaryWithObjectProperties];

The reason for this is that I have a valueEntity which, by protocol, my views all conform to, but I would like to populate an NSManagedObject with the values as well. So I thought that using the NSDictionary as an intermediate step I can get around having to do a category on my NSManagedObject that sets each property manually from the value on my object subclassing NSObject.

With a dictionary I can go:

[myManagedObject setValuesForKeysWithDictionary:dict];

I just can't get the dictionary representation back out once I done the above?

+3  A: 

Yep, the method is:

- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys

You pass in an array of keys representing the object properties that you're interested in, and get back a dictionary containing the property values.

The NSKeyValueCoding protocol defines a number of powerful and highly useful methods; it's a great thing to get familiar with.

http://developer.apple.com/library/ios/#documentation/cocoa/reference/foundation/Protocols/NSKeyValueCoding_Protocol/Reference/Reference.html

There's also a very valuable companion guide:

http://developer.apple.com/library/ios/documentation/cocoa/Conceptual/KeyValueCoding/KeyValueCoding.html#//apple_ref/doc/uid/10000107i

jlehr
Hi jlehr, thank you:) I see that it is not as automatic as the [obj setValuesforKeysWithDictionary:dict], but then again, as Yuji points out, this makes it possible to pick and choose the properties and avoid relationships etc. This is really great as I can now maintain a single array of property names that are shared across objects and this is a much more flexible solution. Thank you again, will get right on the guides.
RickiG
Hey Ricki, no problem :-)
jlehr
+2  A: 

Do you really want to get all the properties? Often it doesn't make sense to get all the properties of an object as a dictionary. For example, if an NSManagedObject contains a relationship, do you want to get it too in the dictionary? If so, how do you want to represent it?

As jlehr said, it's better to feed a set of keys explicitly using dictionaryWithValuesForKeys:.

That said, using the dreaded Objective-C runtime, you can indeed implement makeDictionaryWithObjectProperties. Use class_getPropertyList and property_getName. I won't detail how to do that, because if you do follow this approach, you know what you're doing.

By the way, it's very dangerous for you to assign a JSON object returned from the Internet to an NSManagedObject using setValuesForKeysWithDictionary:. Because, if the JSON object happens to contain an additional key which you don't expect, your code can suddenly crash. So, don't do that.

Another comment: your pseudo-code

NSObject *myObject = [[NSObject alloc] init];
[myObject setValuesForKeysWithDictionary:JSONDict];

doesn't make much sense: yes you can call setValuesForKeysWithDictionary: against NSObject, but it will miserably fail, because you can't setValue:forKey: for any of the entries in JSONDict to a vanilla NSObject. I guess you know that, but I'd like to say that explicitly so that a novice who comes across this page won't be fooled.

Yuji
Hi Yuji and thank you too. I should not go the runtime route just yet:) I'll just make the NSObject example into something more sensible, I am really glad you both caught onto what I was trying to achieve despite the fact that I was lacking the words to describe it precisely. I actually parse, refine and validate my JSON values before they go "onto" the object, but thanks again, I am getting some great pointers from your answers.
RickiG
You're welcome :)
Yuji