RestKit create mapping for nested array

151 views Asked by At

I'm using Rest Kit to parse data from the server. I have this JSON from the server:

{
  "title":""
  "data":
    {
      "container":
                 [
                   {
                     "container_award":
                       [[[{"title":"","image":""}]]]
                   }
                 ],...
    }
}

I need to create the mapping to do this. My problem is in creating the Mapping for the container_award, because i don't know how to get the nested arrays in the mapping for Rest Kit.

There is my mapping, but doesn't work:

RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[Card class]];

[responseMapping addAttributeMappingsFromDictionary:[Card getMapping]];


// if we have keyPath we also cold have subKeyPath

RKObjectMapping *cardContainerArrayMapping = [RKObjectMapping mappingForClass:[CardContainerArray class]];

RKObjectMapping *cardContainerMapping = [RKObjectMapping mappingForClass:[CardContainer class]];
[cardContainerMapping addAttributeMappingsFromDictionary:[CardContainer getMapping]];

RKObjectMapping *containerDataMapping = [RKObjectMapping mappingForClass:[CardContainerData class]];
[containerDataMapping addAttributeMappingsFromDictionary:[CardContainerData getMapping]];


// for three array
RKObjectMapping *containerDataAwardsMapping = [RKObjectMapping mappingForClass:[CardContainerData class]];
[containerDataAwardsMapping addAttributeMappingsFromDictionary:[CardContainerData getMapping]];

RKObjectMapping *array1Mapping = [RKObjectMapping mappingForClass:[NSArray class]];
[array1Mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil
                                                                              toKeyPath:nil
                                                                            withMapping:containerDataAwardsMapping]];


RKObjectMapping *array2Mapping = [RKObjectMapping mappingForClass:[NSArray class]];
[array2Mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil
                                                                              toKeyPath:nil
                                                                            withMapping:array1Mapping]];

[cardContainerMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"container_awards"
                                                                                     toKeyPath:@"container_awards"
                                                                                   withMapping:array2Mapping]];

[cardContainerArrayMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"containers"
                                                                                toKeyPath:@"containers"
                                                                              withMapping:cardContainerMapping]];

[responseMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"data"
                                                                                toKeyPath:@"data"
                                                                              withMapping:cardContainerArrayMapping]];

Edit: The Card Class

@class CardContainerArray;

@interface Card : NSObject

@property(nonatomic,strong) NSString *title;
@property(nonatomic,strong) CardContainerArray *data;

The CardContainerArray Class:

@interface CardContainerArray : NSObject

@property(nonatomic,strong) NSArray *container;

@end

The CardContainer Class: @interface CardContainer : NSObject

@property(nonatomic,strong) NSArray*  container_award;

And the CardContainerData:

@interface CardContainerData : NSObject

@property(nonatomic,strong) NSString *title;
@property(nonatomic,strong) NSString *image;
1

There are 1 answers

8
Wain On

You need a 'container' class to handle the container in your JSON, because you can't index into an array as part of the mapping. That 'container' could be a custom class, or it could be a simple dictionary, it depends how you want the final data to be.

You can alternatively map container into an array on your existing class and then handle the array of dictionaries yourself.

[[[{"title":"","image":""}]]] is pretty rubbish though, that should really be cleaned up as a triple nested array seems illogical...


From your edit, you don't really want to be mapping into NSArray. At best it should be NSMutableArray, but you don't map arrays, you map the contents of arrays.


Dealing with [[[{"title":"","image":""}]]]:

probably the easiest option is to cheat... You already have @property(nonatomic,strong) NSString *title; and @property(nonatomic,strong) NSString *image;, but don't use that in the mapping. Instead, make the mapping simply imageMessyArray and use:

- (NSArray *)imageMessyArray { return @[]; }
- (void)setImageMessyArray:(NSArray *)messyArray {
    NSDictionary *imageDict = [[[messyArray firstObject] firstObject] firstObject];
    self.title = [imageDict objectForKey:@"title"];
    self.image = [imageDict objectForKey:@"image"];
}

it really is messy.

The correct way to do it would be to create an array to CardContainerData transformer, which would basically wrap the same code but encapsulate it more cleanly.