Reputation: 11
I need to map JSON associative array of objects with RestKit(iOS). It looks like object with properties 135,145,423 and objects on it.
{
"135": {
"name" : "Object1",
"property1" : "Value1",
"anotherProperty1" : "Value2"
},
"145": {
"name": "Object2",
"property1" : "Value1",
"anotherProperty1" : "Value2"
},
"423": {
"name": "Object3",
"property1" : "Value1",
"anotherProperty1" : "Value2"
}
}
I've got mapping for single object that works. Mapping performs to CoreData. The only solution i have is to convert associative array to ordinary array and place number to "id" field, but i don't think it's elegant solution.
Is there any right way to perform such mapping directly with RestKit?
Upvotes: 0
Views: 367
Reputation: 11
Here's the solution for my situation.
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
// 1. Create dynamic mapping
RKDynamicMapping* dynamicMapping = [[RKDynamicMapping alloc] init];
// 2. Process every entry separately
dynamicMapping.forceCollectionMapping = YES;
// 3. Set mappings for every object
[dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {
// 4. Mapping to Core Data (Can be replaced with RKObjectMapping if there's no need of CodeData)
RKEntityMapping *singleRouteMapping = [RKEntityMapping mappingForEntityForName:@"Object" inManagedObjectStore:managedObjectStore];
// 5. Walking through all keys (but with dynamicMapping.forceCollectionMapping = YES) there'll be only one. It's better to refactor it.
for (NSString *key in representation) {
// 6. Set mappings for every property exect 'id'
[singleRouteMapping addAttributeMappingsFromDictionary:@{
[NSString stringWithFormat: @"%@.name", key]: @"name",
[NSString stringWithFormat: @"%@.property1", key]: @"property1",
[NSString stringWithFormat: @"%@.anotherProperty1", key]: @"anotherProperty1"
}];
}
// 7. Map 'id' property at last
[singleRouteMapping addAttributeMappingFromKeyOfRepresentationToAttribute: @"id"];
return singleRouteMapping;
}];
RKResponseDescriptor *pluralDescriptor = [RKResponseDescriptor responseDescriptorWithMapping: dynamicMapping
pathPattern: @"/api/objects"
keyPath: nil
statusCodes: statusCodes];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.somesite.com/api/objects"]];
RKManagedObjectRequestOperation *operation = [[RKManagedObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[pluralDescriptor]];
Upvotes: 1
Reputation: 119041
You need to use a dynamic mapping, where the mapping is created specifically for the received keys in the dictionary. You don't say what the destination object is or what your mappings are so this is a general example (for Core Data, but can be changed to plain objects):
RKDynamicMapping* dynamicMapping = [[RKDynamicMapping alloc] init];
[dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {
RKEntityMapping* typeMapping = [RKEntityMapping mappingForEntityForName:@"..." inManagedObjectStore:objectStore];
for (NSString *key in representation) {
NSDictionary *type = [representation objectForKey:key];
[typeMapping addAttributeMappingsFromDictionary:@{
[NSString stringWithFormat:@"%@.name", key]: @"name"}];
}
return typeMapping;
}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:dynamicMapping
pathPattern:...
keyPath:nil
statusCodes:[NSIndexSet indexSetWithIndex:200]];
This basically strips out the numbers and throws them away. You could include them if required by configuring the dynamic mapping.
Upvotes: 0