I'm trying to map the following JSON response with Restkit:
{
"container": {
"id": 1,
"infos": [
{
"id": 1,
"name": "...",
"type": 6,
"value": {
"d0": {
"periods": [
{ "close": "12.30", "open": "09.00" },
{ "close": "19.30", "open": "15.30" }
]
},
"d1": {...},
"d2": {...},
"d3": {...},
"d4": {...},
"d5": {...},
"d6": {...}
},
"created": "2015-12-08T17:18:05.732Z",
}
]
}
}
where the structure inside "value"
is dynamic - that is can vary according to the type of response returned by the API. The object classes implemented are as follows:
@interface CFFContainer : NSObject
@property (nonatomic, retain) NSNumber *identifier;
@property (nonatomic, retain) NSMutableArray *infos;
@end
@interface CFFInfo : NSObject
@property (nonatomic, retain) NSNumber *identifier;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSNumber *type;
@property (nonatomic, retain) NSMutableDictionary *value;
@property (nonatomic, retain) NSDate *created;
@end
@interface CFFOpeningTimes : NSObject
@property (nonatomic, retain) CFFOpeningDay *d0;
@property (nonatomic, retain) CFFOpeningDay *d1;
@property (nonatomic, retain) CFFOpeningDay *d2;
@property (nonatomic, retain) CFFOpeningDay *d3;
@property (nonatomic, retain) CFFOpeningDay *d4;
@property (nonatomic, retain) CFFOpeningDay *d5;
@property (nonatomic, retain) CFFOpeningDay *d6;
@end
@interface CFFOpeningDay : NSObject
@property (nonatomic, retain) NSMutableArray *periods;
@end
@interface CFFPeriod : NSObject
@property(nonatomic, retain) NSString *open;
@property(nonatomic, retain) NSString *close;
@end
(not sure if I can use a generic NSMutableDictionary for CFFInfo.value
, but I cannot assign a specific type, since I do not know what the actual structure of the entity will be).
And finally the mappings:
// Container.
[containerMapping addAttributeMappingsFromDictionary:@{@"identifier": @"id"}];
RKRelationshipMapping *infoMapping =
[RKRelationshipMapping relationshipMappingFromKeyPath:@"infos"
toKeyPath:@"infos"
withMapping:[CFFInfo mapping]];
[responseMapping addPropertyMapping:infoMapping];
// Info.
[infoMapping addAttributeMappingsFromDictionary:@{@"identifier": @"id", @"name": @"name", @"type": @"type", @"created": @"created"}];
// Create dynamic mapping for surveys, opening times, news, etc.
RKDynamicMapping *dynamicMapping = [[RKDynamicMapping alloc] init];
[dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {
if ([[representation valueForKey:@"name"] containsString:@"Survey"]) {
return [CFFSurvey mapping];
} else if ([representation valueForKey:@"d0"] != nil) {
return [CFFOpeningTimes mapping];
} else if ([[representation valueForKey:@"name"] containsString:@"News"]) {
return [CFFNews mapping];
}
return nil;
}];
RKRelationshipMapping *valueMapping =
[RKRelationshipMapping relationshipMappingFromKeyPath:@"value"
toKeyPath:@"value"
withMapping:dynamicMapping];
[infoMapping addPropertyMapping: valueMapping];
// Opening times.
RKRelationshipMapping * d0mapping =
[RKRelationshipMapping relationshipMappingFromKeyPath:@"d0"
toKeyPath:@"d0"
withMapping:[CFFOpeningDay mapping]];
[openingTimesMapping addPropertyMapping:d0mapping];
// ... same for d1, d2, d3, d4, d5, d6...
// Opening day.
RKRelationshipMapping *periodsMapping =
[RKRelationshipMapping relationshipMappingFromKeyPath:@"periods"
toKeyPath:@"periods"
withMapping:[CFFPeriod mapping]];
[periodMapping addPropertyMapping:periodsMapping];
// Period.
[periodMapping addAttributeMappingsFromDictionary:@{@"open": @"open", @"close": @"close"}];
All the mapping operations run smoothly, but although the logs show the matches for all the entities, in the end I get a container.infos[0].value
object with 0 key/value pairs. The logs actually says:
restkit.object_mapping:RKMappingOperation.m:887
Mapped relationship object from keyPath 'value' to 'value'.
Value: <CFFOpeningTimes: 0x796eb6d0>
The weird thing is that if a different dynamic mapping is applied for value
(such as [CFFSurvey mapping]
) the mapped object contains the correct data. I also tried to debug the execution of the mapping operations, and as far as I could see, the mapNestedObject:toObject:parent:withRelationshipMapping:metadataList:
method in RKMappingOperation.m - line 883 seems not to copy the mapped nested object to the destination object returned.
I'm really going mad about this. Any ideas about where the problem might be?
答案 0 :(得分:0)
好的我发现了问题所在。正如我所指出的,NSMutableDictionary
的{{1}}类型显然不符合可能映射到它上面的通用结构。
所以我只是用更通用的CFFInfo.value
替换了那个类型。
NSObject<NSCopying>
我添加了@interface CFFInfo : NSObject
@property (nonatomic, retain) NSNumber *identifier;
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSNumber *type;
@property (nonatomic, retain) NSObject<NSCopying> *value;
@property (nonatomic, retain) NSDate *created;
@end
协议并为NSCopying
类和级联中使用的类实现了copyWithZone:
方法,以确保正确复制所有数据,以防副本那个对象是必需的。