14

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?

RickiG
  • 11,380
  • 13
  • 81
  • 120

3 Answers3

17

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
  • 15,557
  • 5
  • 43
  • 45
  • 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 Sep 14 '10 at 20:07
5

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
  • 34,103
  • 3
  • 70
  • 88
  • 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 Sep 14 '10 at 20:18
1

This guy here used some runtime magic to get all the properties declared on an object and got the dictionary without manually providing the property names.

And there'e also this nice github repo i found, They pretty much do the same trick, but in a nice package. They also have the ability to create a json or plist from an object.

Alex Zak
  • 1,924
  • 2
  • 18
  • 26
  • [AutoMagicCoding](https://github.com/psineur/NSObject-AutomagicCoding) was really usefull for me, just what i was looking for :) – Alex75 Apr 08 '13 at 12:07