Alx
Alx

Reputation: 6285

Nested Object Mapping using RestKit

I'm struggeling a wee bit with following JSON I'm trying to map into an object structure:

- Group
  + label
  + type
  + children
    - childname1
       + label
       + type
       + value

    - childname2
       + label
       + type
       + value

I do have a Groupclass

@interface CameraGroup : NSObject
@property (nonatomic, copy) NSString *label;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSDictionary *children;
@end

and a Child class

@property (nonatomic, copy) NSString *label;
@property (nonatomic, copy) NSString *type;
@property (nonatomic, copy) NSString *value;

My JSON looks like following:

{
    "actions": {
        "label": "Action List",
        "type": "section",
        "children": {
            "action1": {
                "label": "This is action1",
                "type": "toggle",
                "value": 0
            },
            "action2": {
                "label": "This is action2",
                "type": "range",
                "value": 0
            },
            "action3": {
                "label": "This is action3",
                "type": "toggle",
                "value": 0
            }
        }
    }
}

I'm trying to end up with a single Object of Group, holding an NSDictionary (children) with key-value pairs of actions (e.g. action1 = key and child object of label,type and value ) using RestKit.

I'm using following snippet but always end up with a singel, empty child object:

RKObjectMapping *mappingChild = [RKObjectMapping mappingForClass:[Child class]];
  [mappingSetting addAttributeMappingsFromDictionary:@{
                                                @"label": @"label",
                                                @"type":  @"type",
                                                @"value": @"value"
                                                }];

  RKObjectMapping *mappingGroup = [RKObjectMapping mappingForClass:[Group class]];
  [mappingGroup addAttributeMappingsFromDictionary:@{
                                                       @"label": @"label",
                                                       @"type":  @"type"
                                                       }];
  [mappingGroup addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"children" toKeyPath:@"children" withMapping:mappingSetting]];


  NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); 
  RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mappingGroup method:RKRequestMethodAny pathPattern:@"/action" keyPath:@"actions" statusCodes:statusCodes];

  NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://192.168.178.1:1337/actions"]];
  RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:@[responseDescriptor]];
  [operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
    Group *group = [result firstObject];
    NSLog(@"Mapped the group: %@ of type %@ with children %i", article.label, article.label, [group.children count]);
  } failure:^(RKObjectRequestOperation *operation, NSError *error) {
    NSLog(@"Failed with error: %@", [error localizedDescription]);
  }];
  [operation start];

So is there any way how to Map the NSDictionary part without actually knowing that "action1" is named "action1"??

Upvotes: 2

Views: 2403

Answers (1)

Alx
Alx

Reputation: 6285

After playing around I found a solution which seems to work. The responseDescriptorgets the mapping of the Groupwhich has a Relationship Mapping to a dynamicMappingwhich iterates over all childnodes and maps the childMapping

RKObjectMapping *mappingChild = [RKObjectMapping mappingForClass:[Child class]];

  [mappingSetting addAttributeMappingsFromDictionary:@{
                                                       @"label" : @"label",
                                                       @"type" : @"type",
                                                       @"value" : @"value"
                                                       }];

  RKDynamicMapping* dynamicMapping = [RKDynamicMapping new];
  [dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {

    NSArray *keys = [representation allKeys];

    RKObjectMapping *dataMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];

    for (NSString *key in keys) {
      [dataMapping addRelationshipMappingWithSourceKeyPath:key mapping:mappingChild];
    }

    return dataMapping;

  }];

  RKObjectMapping *mappingGroup = [RKObjectMapping mappingForClass:[Group class]];
  [Group addAttributeMappingsFromDictionary:@{
                                                     @"label": @"label",
                                                     @"type":  @"type"
                                                     }];

  [Group addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"children" toKeyPath:@"children" withMapping:dynamicMapping]];







  NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); 
  RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mappingGroup
                                                                                          method:RKRequestMethodAny
                                                                                     pathPattern:@"/actions"
                                                                                         keyPath:@"actions"
                                                                                     statusCodes:statusCodes];

Upvotes: 4

Related Questions