I've been having issues with this issue for several days now, and would really appreciate it if someone will be able to provide some guidance or even a full code solution for this.
I'm trying to perform dynamic object mapping to a JSON string in Objective C using RestKit and can't seem to get the right values.
This is an example to the kind of JSON response I need to parse:
{
"Boy" :
{
"favoriteClass" : "math",
"basicInfo" :
{
"name" : "John",
"age" : 10,
"type" : 1
}
"friends" :
[
{
"Boy" :
{
"favoriteClass" : "PE"
"basicInfo" :
{
"name" : "Bill",
"age" : 12,
"type" : 1
}
"friends" : []
},
"Girl" :
{
"favoriteTeacher" : "Mrs. Manson"
"basicInfo" :
{
"name" : "Sara",
"age" : 11,
"type" : 2
}
"friends" : []
},
"Girl" :
{
"favoriteTeacher" : "Mr. Chase"
"basicInfo" :
{
"name" : "Ronda",
"age" : 9,
"type" : 2
}
"friends" : []
}
}
]
}
}
Meaning, I have two types of classes: a Buy class and a Girl class.
They each have different fields (favoriteClass for the boys and favoriteTeacher for the girls), but the both have a basicInfo field, which contains exactly the same structure.
I can tell which should be mapped to the Boy class and which should be mapped to the Girl class with using the name of the record in the array ("Boy" or "Girl"), or by the "type" field's value within the "basicInfo" record (1 for boys and 2 for girls).
The friends array for both a Boy and a Girl class can contain instances of both boys and girls.
Can anybody please give me some pointers on how this can be done?
Any help will be greatly appreciated.
Thanks,
I just started looking at RestKit today, so I am far from an authority. However, looking at Blake's excellent documentation, it seems to me that you are overly complicating this (your posted JSON does not validate BTW). Unless you have a specific need to have a BasicInfo
object, I'd remove it and configure your JSON thus:
{
"people": [
{
"age": 10,
"favoriteClass": "math",
"name": "John",
"type": 1,
"friends": [
{
"age": 12,
"favoriteClass": "PE",
"friends": [],
"name": "Bill",
"type": 1
},
{
"age": 11,
"favoriteTeacher": "Mrs. Manson",
"friends": [],
"name": "Sara",
"type": 2
},
{
"age": 9,
"favoriteTeacher": "Mr. Chase",
"friends": [],
"name": "Ronda",
"type": 2
}
]
}
]
}
Then you should be able to utilize approach (1) that he describes in the Dynamic Object Mapping section of the Object Mapping document. It appears to me that the only difference you have in comparison with the example he gives is that you have some additional ivars in each of the Boy
and Girl
classes, and you are using an number rather than a string to identify Boy
vs Girl
. You can deal with that by modifying the declarations he gives to be:
// Basic setup
RKObjectMapping* boyMapping = [RKObjectMapping mappingForClass:[Boy class]];
[boyMapping mapAttributes:@"age", @"name", @"favoriteClass",nil];
RKObjectMapping* girlMapping = [RKObjectMapping mappingForClass:[Girl class]];
[girlMapping mapAttributes:@"age", @"name", @"favoriteTeacher", nil];
// Configure the dynamic mapping via matchers
[dynamicMapping setObjectMapping:boyMapping whenValueOfKeyPath:@"type" isEqualTo:@"1"];
[dynamicMapping setObjectMapping:girlMapping whenValueOfKeyPath:@"type" isEqualTo:@"2"];
The type of the matcher may not be quite right -- as I said, I just started reading this stuff today.
Just go through the hierarchy in a disciplined way.
//pseudo code
for (id child in JSONObject) {
if (it is a boy) create new boy object;
else create new girl object;
fill in the info;
for (id child in friends) {
if (it is a boy) create new boy object;
else create new girl object;
fill in the info;
}
}
Of course the whole data scheme is ridiculously repetitive. In my opinion, you should have only one class Child that anyway has an attribute basicInfo.type
that identifies it as boy or girl, so no need to have an extra class.
Also, if you have a list of children who are friends with each other, you will end up listing many children multiple times. Much better would be to have a simple array with unique IDs in the friends field.
You simply need to use a JSON parser like SBJSON, SBJSON can parse the data you receive like so:
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *received = [parser objectWithData:data];
However, if you want to use Restkit, it has a built in parser also. I believe it would work something like this:
- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response
{
RKJSONParser* parser = [RKJSONParser new];
NSDictionary *dict = [parser objectFromString:[response bodyAsString]];
}
I hope that helps you.