Can't map nested RestKit object - ios

I have a problem, can't map a nested object of json. The problem is with the 'capacities' key.
This is the error:
restkit.object_mapping:RKMappingOperation.m:830 Did not find mappable relationship value keyPath 'capacities'
I know that the problem is with the mapping itself, but just can't figure what:
RKObjectMapping *capacityMapping = [RKObjectMapping mappingForClass:[Capacity class]];
[capacityMapping addAttributeMappingsFromDictionary:#{ #"capacityText" : #"capacityText",
#"priceDescriptionText" : #"priceDescriptionText",
#"priceText" : #"priceText" }];
RKObjectMapping *colorsMapping = [RKObjectMapping mappingForClass:[Colors class]];
[colorsMapping addAttributeMappingsFromDictionary:#{ #"ID" : #"idNum",
#"Name" : #"name",
#"colorHex" : #"colorHex",
#"imageUrl" : #"imageURL" }];
RKObjectMapping *deviceDataMapping = [RKObjectMapping mappingForClass:[DeviceData class]];
[deviceDataMapping addAttributeMappingsFromDictionary:#{ #"device.ID" : #"idNum",
#"device.Name" : #"name",
#"device.additionalFeatures" : #"additionalFeatures",
#"device.deviceName" : #"deviceName",
#"device.mainFeatures" : #"mainFeatures",
#"device.supportPagesLinks" : #"supportPagesLinks",
#"device.whatsInTheKit" : #"whatsInTheKit" }];
[deviceDataMapping addRelationshipMappingWithSourceKeyPath:#"capacities" mapping:capacityMapping];
[capacityMapping addRelationshipMappingWithSourceKeyPath:#"colors" mapping:colorsMapping];
[deviceDataMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"responseError"
toKeyPath:#"responseError"
withMapping:errorMapping]];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:deviceDataMapping
method:RKRequestMethodGET
pathPattern:#"devices/:boneID"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
This is the DeviceData class:
#interface DeviceData : NSObject
#property (nonatomic) ResponseError *responseError;
#property (copy, nonatomic) NSString *idNum;
#property (copy, nonatomic) NSString *name;
#property (copy, nonatomic) NSString *additionalFeatures;
#property (copy, nonatomic) NSString *deviceName;
#property (copy, nonatomic) NSString *mainFeatures;
#property (copy, nonatomic) NSString *supportPagesLinks;
#property (copy, nonatomic) NSString *whatsInTheKit;
#property (nonatomic) NSArray *capacities;
#property (assign, nonatomic) NSInteger boneID;
#end
This is the Capacity class:
#interface Capacity : NSObject
#property (copy, nonatomic) NSString *capacityText;
#property (nonatomic) NSArray *colors;
#property (copy, nonatomic) NSString *priceDescriptionText;
#property (copy, nonatomic) NSString *priceText;
#end
This is the Colors class:
#interface Colors : NSObject
#property (copy, nonatomic) NSString *idNum;
#property (copy, nonatomic) NSString *name;
#property (copy, nonatomic) NSString *colorHex;
#property (copy, nonatomic) NSString *imageURL;
#end
This is the json:
{
"responseError": null,
"device": {
"ID": null,
"Name": null,
"additionalFeatures": "additional features text",
"capacities": [
{
"capacityText": "16GB",
"colors": [
{
"ID": null,
"Name": null,
"colorHex": "#a68f76",
"imageUrl": "iphone_5s_black.png"
},
{
"ID": null,
"Name": null,
"colorHex": "#a9a9a9",
"imageUrl": "iphone_5s_black.png"
},
{
"ID": null,
"Name": null,
"colorHex": "#616065",
"imageUrl": "iphone_5s_black.png"
}
],
"priceDescriptionText": “iPhone 5S",
"priceText": "750$"
},{
"capacityText": “32GB",
"colors": [
{
"ID": null,
"Name": null,
"colorHex": "#a68f76",
"imageUrl": "iphone_5s_black.png"
},
{
"ID": null,
"Name": null,
"colorHex": "#a9a9a9",
"imageUrl": “iphone_5s_black.png"
},
{
"ID": null,
"Name": null,
"colorHex": "#616065",
"imageUrl": “iphone_5s_black.png"
}
],
"priceDescriptionText": “iPhone 5S",
"priceText": "750$"
}
],
"deviceName": "iPhone 5s",
"mainFeatures": “some main features text",
"supportPagesLinks": [
{
"linkText": “restore",
"linkUrl": “restore.pdf"
}],
"whatsInTheKit": "what inside the kit text"
}
}

Because your response descriptor has a nil key path and you use device.xxx in all source key paths of the deviceMapping you need to have an explicit relationship mapping so you can specify the source and destination key paths:
RKRelationshipMapping *capacitiesMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:#"device.capacities" toKeyPath:#"capacities" withMapping:capacityMapping];
[deviceDataMapping addPropertyMapping:capacitiesMapping];

Related

Parsing nested json in iOS using Mantle

I'm trying to parse data received from a service using the framework Mantle. The json has nested data and I am having problems to parse it. The json is like the following:
{
"sections": [
{
"title": "title1",
"level": 1,
"content": [
{
"type": "type1",
"text": "text1"
}
],
"images": []
},
{
"title": "title2",
"level": 2,
"content": [
{
"type": "type2",
"text": "text2"
},
{
"type": "type9",
"text": "text9"
},
{
"type": "type4",
"text": "text4"
},
{
"type": "type6",
"text": "text6"
}
],
"images": [
{
"src": "http://cvbcvcv",
"caption": "caption"
}
]
}]
}
The class that I am using is:
// MainObject.h
#interface MainObject : MTLModel <MTLJSONSerializing>
#property (strong, nonatomic) NSArray *sectionsArray;
+ (NSValueTransformer *)sectionsArrayJSONTransformer;
#end
#interface Section : MTLModel <MTLJSONSerializing>
#property (strong, nonatomic) NSString *title;
#property (assign, nonatomic) NSString *level;
#property (strong, nonatomic) NSArray *content;
#property (strong, nonatomic) NSArray *images;
+ (NSValueTransformer *)contentJSONTransformer;
+ (NSValueTransformer *)imagesJSONTransformer;
#end
#interface Content : MTLModel <MTLJSONSerializing>
#property (strong, nonatomic) NSString *type;
#property (strong, nonatomic) NSString *text;
#end
#interface Image : MTLModel <MTLJSONSerializing>
#property (strong, nonatomic) NSString *src;
#property (strong, nonatomic) NSString *caption;
#end
and
//MainObject.m
#implementation MainObject
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return #{
#"sectionsArray" : #"sections",};
}
+ (NSValueTransformer *)sectionsArrayJSONTransformer
{
return [MTLJSONAdapter dictionaryTransformerWithModelClass:[Section class]];
}
#end
#implementation Section
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return #{
#"title" : #"title",
#"level" : #"level",
#"content" : #"content",
#"images" : #"images",};
}
+ (NSValueTransformer *)contentJSONTransformer
{
return [MTLJSONAdapter arrayTransformerWithModelClass:[Content class]];
}
+ (NSValueTransformer *)imagesJSONTransformer
{
return [MTLJSONAdapter arrayTransformerWithModelClass:[Image class]];
}
#end
#implementation Content
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return #{
#"type" : #"type",
#"text" : #"text",};
}
#end
#implementation Image
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
return #{
#"src" : #"src",
#"caption" : #"caption",};
}
#end
Then, when I make the call to the service and try to parse the json with the following code, being responseObject the data obtained from server, the data appears nil:
for (NSArray *array in [responseObject valueForKey:#"sections"]) {
NSArray *seccionArray = [MTLJSONAdapter modelsOfClass:[Section class] fromJSONArray:array error:nil];
}
I have tried a lot of ways to parse this data well, but the app always crashes or returns nil. I hope you can help me to solve this
Why can't just one line using NSJSONSerialization?
NSMutableDictionary *yourArray = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil];
Then you fetch what you want from your array...

JSONModel: Model Collection to JSON and Add Collection Manually

Lets say I have this Model.
#protocol ProductModel
#end
#interface ProductModel : JSONModel
#property (assign, nonatomic) int id;
#property (strong, nonatomic) NSString* name;
#property (assign, nonatomic) float price;
#end
#implementation ProductModel
#end
#interface OrderModel : JSONModel
#property (assign, nonatomic) int order_id;
#property (assign, nonatomic) float total_price;
#property (strong, nonatomic) NSArray<ProductModel>* products;
#end
#implementation OrderModel
#end
Questions:
How I can add products in this array?
Then how I can produce the following JSON.
"products" : [
{
"id": "123",
"name": "Product #1",
"price": 12.95
},
{
"id": "137",
"name": "Product #2",
"price": 82.95
}
]
or the whole object.
{
"order_id": 104,
"total_price": 103.45,
"products" : [
{
"id": "123",
"name": "Product #1",
"price": 12.95
},
{
"id": "137",
"name": "Product #2",
"price": 82.95
}
]
}
I think BWJSONMatcher can help you out in a extremely neat way:
ProductModel *productModel1 = [[ProductModel alloc] init];
productModel1.id = 123;
productModel1.name = #"Product #1";
productModel1.price = 12.95;
ProductModel *productModel2 = [[ProductModel alloc] init];
productModel2.id = 137;
productModel2.name = #"Product #2";
productModel2.price = 82.95;
OrderModel *orderModel = [[OrderModel alloc] init];
orderModel.order_id = 104;
orderModel.total_price = 103.45;
orderModel.products = #[productModel1, productModel2];
NSString *producedJSON = [orderModel toJSONString];

Nested JSONModel in iOS to get info from Instagram

I'm working with JSONModel to parse Instagram info from JSON to a model in my iOS app. I have tried many ways to achieve it but I can't. Three main parts of the response are data, meta and pagination. I have created the model and the model is always NULL. I'm going to attach the response I'm trying to parse, my models and how I'm processing the response. I think it could be a problem with the structure but I don't know what I'm doing wrong. Thanks for your help.
Response from Instagram
{
"data": [
{
"attribution": null,
"caption": {
"created_time": "1387987595",
"from": {
"full_name": "Camilo Sacanamboy",
"id": "268167404",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_268167404_75sq_1386784112.jpg",
"username": "csacanam"
},
"id": "618807262892627401",
"text": "Navidad :)"
},
"comments": {
"count": 2,
"data": [
{
"created_time": "1387987956",
"from": {
"full_name": "Luisa Bellydancer",
"id": "548519361",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_548519361_75sq_1398196543.jpg",
"username": "luisacantillo"
},
"id": "618810289837938356",
"text": "Te amo beb\u00e9"
},
{
"created_time": "1403666639",
"from": {
"full_name": "Camilo Sacanamboy",
"id": "268167404",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_268167404_75sq_1386784112.jpg",
"username": "csacanam"
},
"id": "750332614214522476",
"text": "#sacanamboy"
}
]
},
"created_time": "1387987595",
"filter": "Walden",
"id": "618807262548694878_268167404",
"images": {
"low_resolution": {
"height": 306,
"url": "http://scontent-b.cdninstagram.com/hphotos-xpf1/t51.2885-15/1515365_559830227444878_1414305160_a.jpg",
"width": 306
},
"standard_resolution": {
"height": 640,
"url": "http://scontent-b.cdninstagram.com/hphotos-xpf1/t51.2885-15/1515365_559830227444878_1414305160_n.jpg",
"width": 640
},
"thumbnail": {
"height": 150,
"url": "http://scontent-b.cdninstagram.com/hphotos-xpf1/t51.2885-15/1515365_559830227444878_1414305160_s.jpg",
"width": 150
}
},
"likes": {
"count": 2,
"data": [
{
"full_name": "Luisa Bellydancer",
"id": "548519361",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_548519361_75sq_1398196543.jpg",
"username": "luisacantillo"
},
{
"full_name": "Steven Zambrano",
"id": "198842014",
"profile_picture": "http://photos-d.ak.instagram.com/hphotos-ak-xpa1/10354559_1419915091614315_879045002_a.jpg",
"username": "steven_zambrano"
}
]
},
"link": "http://instagram.com/p/iWce08pZde/",
"location": null,
"tags": [
"sacanamboy"
],
"type": "image",
"user": {
"bio": "",
"full_name": "Camilo Sacanamboy",
"id": "268167404",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_268167404_75sq_1386784112.jpg",
"username": "csacanam",
"website": ""
},
"users_in_photo": [
{
"position": {
"x": 0.39722222,
"y": 0.15416667
},
"user": {
"full_name": "Luisa Bellydancer",
"id": "548519361",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_548519361_75sq_1398196543.jpg",
"username": "luisacantillo"
}
},
{
"position": {
"x": 0.55138886,
"y": 0.09583333
},
"user": {
"full_name": "Camilo Sacanamboy",
"id": "268167404",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_268167404_75sq_1386784112.jpg",
"username": "csacanam"
}
}
]
},
{
"attribution": null,
"caption": {
"created_time": "1391910835",
"from": {
"full_name": "Camilo Sacanamboy",
"id": "268167404",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_268167404_75sq_1386784112.jpg",
"username": "csacanam"
},
"id": "651717783438333290",
"text": "Vista de Bogot\u00e1"
},
"comments": {
"count": 1,
"data": [
{
"created_time": "1403665438",
"from": {
"full_name": "Camilo Sacanamboy",
"id": "268167404",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_268167404_75sq_1386784112.jpg",
"username": "csacanam"
},
"id": "750322542532990878",
"text": "#sacanamboy"
}
]
},
"created_time": "1391910835",
"filter": "Hudson",
"id": "651717782742079012_268167404",
"images": {
"low_resolution": {
"height": 306,
"url": "http://scontent-b.cdninstagram.com/hphotos-xfp1/t51.2885-15/1889287_611340528913277_403885343_a.jpg",
"width": 306
},
"standard_resolution": {
"height": 640,
"url": "http://scontent-b.cdninstagram.com/hphotos-xfp1/t51.2885-15/1889287_611340528913277_403885343_n.jpg",
"width": 640
},
"thumbnail": {
"height": 150,
"url": "http://scontent-b.cdninstagram.com/hphotos-xfp1/t51.2885-15/1889287_611340528913277_403885343_s.jpg",
"width": 150
}
},
"likes": {
"count": 3,
"data": [
{
"full_name": "Luisa Bellydancer",
"id": "548519361",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_548519361_75sq_1398196543.jpg",
"username": "luisacantillo"
},
{
"full_name": "Stiven Sepulveda Casta\u00f1o",
"id": "270408040",
"profile_picture": "http://photos-a.ak.instagram.com/hphotos-ak-xfp1/10354393_1459814907595448_1770710968_a.jpg",
"username": "johntato"
},
{
"full_name": "Julian Garcia",
"id": "318551590",
"profile_picture": "http://photos-e.ak.instagram.com/hphotos-ak-xaf1/10413240_284995708339980_626057267_a.jpg",
"username": "juliangarcia20"
}
]
},
"link": "http://instagram.com/p/kLXd7WJZYk/",
"location": {
"id": 1187760,
"latitude": 4.67413252,
"longitude": -74.037993338,
"name": "Mirador de La Calera, Bogota"
},
"tags": [
"sacanamboy"
],
"type": "image",
"user": {
"bio": "",
"full_name": "Camilo Sacanamboy",
"id": "268167404",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_268167404_75sq_1386784112.jpg",
"username": "csacanam",
"website": ""
},
"users_in_photo": [
{
"position": {
"x": 0.3625,
"y": 0.54444444
},
"user": {
"full_name": "Luisa Bellydancer",
"id": "548519361",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_548519361_75sq_1398196543.jpg",
"username": "luisacantillo"
}
},
{
"position": {
"x": 0.60694444,
"y": 0.42222223
},
"user": {
"full_name": "Camilo Sacanamboy",
"id": "268167404",
"profile_picture": "http://images.ak.instagram.com/profiles/profile_268167404_75sq_1386784112.jpg",
"username": "csacanam"
}
}
]
}
],
"meta": {
"code": 200
},
"pagination": {
"deprecation_warning": "next_max_id and min_id are deprecated for this endpoint; use min_tag_id and max_tag_id instead",
"min_tag_id": "1403666639684031",
"next_min_id": "1403666639684031"
}
}
Models
#interface TagPicturesInstagram : JSONModel
#property (strong,nonatomic) NSArray<PictureInstagram> *data;
#property (strong,nonatomic) MetaInstagram *meta;
#property (strong,nonatomic) PaginationInstagram *pagination;
#end
#protocol PictureInstagram
#end
#interface PictureInstagram : JSONModel
#property (strong,nonatomic) NSString<Optional> *attribution;
#property (strong,nonatomic) CaptionInstagram *caption;
#property (strong,nonatomic) CommentsInstagram *comments;
#property (strong,nonatomic) NSString *created_time;
#property (strong,nonatomic) NSString *filter;
#property (strong,nonatomic) NSString *id;
#property (strong,nonatomic) ImagesInstagram *images;
#property (strong,nonatomic) LikesInstagram *likes;
#property (strong,nonatomic) NSString *link;
#property (strong,nonatomic) LocationInstagram<Optional> *location;
#property (strong,nonatomic) NSArray<Optional> *tags;
#property (strong,nonatomic) NSString *type;
#property (strong,nonatomic) UserInstagram *user;
#property (strong,nonatomic) NSArray<UserInPhoto> *users_in_photo;
//#property (assign,nonatomic) BOOL user_has_liked;
//#property (strong,nonatomic) NSString<Optional> *website;
#end
#interface MetaInstagram : JSONModel
#property (assign,nonatomic) int code;
#property (strong,nonatomic) NSString<Optional> *error_type;
#property (strong,nonatomic) NSString<Optional> *error_message;
#end
#interface PaginationInstagram : JSONModel
#property (strong,nonatomic) NSString<Optional> *next_max_tag_id;
#property (strong,nonatomic) NSString<Optional> *deprecation_warning;
#property (strong,nonatomic) NSString<Optional> *next_max_id;
#property (strong,nonatomic) NSString<Optional> *next_min_id;
#property (strong,nonatomic) NSString<Optional> *min_tag_id;
#property (strong,nonatomic) NSString<Optional> *next_url;
#end
#interface CaptionInstagram : JSONModel
#property (strong,nonatomic) NSString *created_time;
#property (strong,nonatomic) FromInstagram *from;
#property (strong,nonatomic) NSString *id;
#property (strong,nonatomic) NSString<Optional> *text;
#end
#interface CommentsInstagram : JSONModel
#property (assign,nonatomic) int count;
#property (strong,nonatomic) NSArray<CommentInstagram> *data;
#end
#interface ImagesInstagram : JSONModel
#property (strong,nonatomic) ImgInstagram *low_resolution;
#property (strong,nonatomic) ImgInstagram *standard_resolution;
#property (strong,nonatomic) ImgInstagram *thumbnail;
#end
#interface LikesInstagram : JSONModel
#property (assign,nonatomic) int count;
#property (strong,nonatomic) NSArray<FromInstagram> *data;
#end
#interface LocationInstagram : JSONModel
#property (assign,nonatomic) int id;
#property (assign,nonatomic) double latitude;
#property (assign,nonatomic) double longitude;
#property (strong,nonatomic) NSString *name;
#end
#interface UserInstagram : JSONModel
#property (strong,nonatomic) NSString<Optional> *bio;
#property (strong,nonatomic) NSString *full_name;
#property (strong,nonatomic) NSString *id;
#property (strong,nonatomic) NSString *profile_picture;
#property (strong,nonatomic) NSString *username;
#property (strong,nonatomic) NSString<Optional> *website;
#end
#interface UserInPhoto : JSONModel
#property (strong,nonatomic) PositionTagInstagram *position;
#property (strong,nonatomic) FromInstagram *user;
#end
#protocol FromInstagram
#end
#interface FromInstagram : JSONModel
#property (strong,nonatomic) NSString *full_name;
#property (strong,nonatomic) NSString *id;
#property (strong,nonatomic) NSString *profile_picture;
#property (strong,nonatomic) NSString *username;
#end
#protocol CommentInstagram
#end
#interface CommentInstagram : JSONModel
#property (strong,nonatomic) NSString *created_time;
#property (strong,nonatomic) FromInstagram *from;
#property (strong,nonatomic) NSString *id;
#property (strong,nonatomic) NSString *text;
#end
#protocol ImgInstagram
#end
#interface ImgInstagram : JSONModel
#property (assign,nonatomic) double height;
#property (strong,nonatomic) NSString *url;
#property (assign,nonatomic) double width;
#end
#interface PositionTagInstagram : JSONModel
#property (assign,nonatomic) double x;
#property (assign,nonatomic) double y;
#end
Getting response with AFNetworking
-(void) loadInstagramInfo
{
//1. Create request
NSString *string = [NSString stringWithFormat:#"%#", BaseURLString];
NSURL *url = [NSURL URLWithString:string];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//2. Do request with AFNetworking
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString *json = [responseObject description];
NSError *err = nil;
self.pictures = [[TagPicturesInstagram alloc]initWithString:json error:&err];
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error cargando fotos");
/*
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Error Retrieving Weather"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"Ok"
otherButtonTitles:nil];
[alertView show];*/
}];
[operation start];
}
I created one .txt file with your json response and then fetch data that you required.
NSMutableArray *arrayData = [[NSMutableArray alloc]init];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:#"json.txt"];
// NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:NULL];
NSData *data = [NSData dataWithContentsOfFile:filePath];
NSMutableDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:nil];
NSLog(#"json = %#",json);
for (NSDictionary* dic in [json objectForKey:#"data"]) {
[arrayData addObject:dic];
}
NSLog(#"array data = %#",arrayData);
NSLog(#"meta code = %#",[[json valueForKey:#"meta"] valueForKey:#"code"]);
NSLog(#"pagination deprecation_warning = %#",[[json valueForKey:#"pagination"] valueForKey:#"deprecation_warning"]);
NSLog(#"pagination min_tag_id = %#",[[json valueForKey:#"pagination"] valueForKey:#"min_tag_id"]);
NSLog(#"pagination next_min_id = %#",[[json valueForKey:#"pagination"] valueForKey:#"next_min_id"]);
follow above code and do changes in your model. Hope this will help you.
This is a response string.
meta code = 200
pagination deprecation_warning = next_max_id and min_id are deprecated for this endpoint; use min_tag_id and max_tag_id instead
pagination deprecation_warning = 1403666639684031
pagination deprecation_warning = 1403666639684031

Can't map relationship into array in restkit

So, I have this result from the service:
{
"CustomerPromotions": [
{
"BottomTitle": "Thank you",
"IconURL": "",
"MiddleText": "399$",
"PromotionID": "123B456",
"SortOrder": 0,
"TopTitle": "Welcome to"
}
],
"CustomerStatus": 1,
"CustomerVoucherIcon": "",
"CustomerVoucherText": "",
"CustomerVoucherTitle": "",
"ErrorID": 0,
"ErrorMessage": "",
"FeedbackIndicator": false,
"FeedbackLowerText": "",
"FeedbackTitle": "",
"HPTopTitle": "Hello world",
"LocalCurrencySign": "$",
"LocalCurrencyValue": "3.30",
"LocalTime": "20:30",
"LocalWeather": "-5",
"PopUpTopTitle": ""
}
But for some reason I can't map CustomerPromotions it into an array, this is how my 2 objects looks like:
This is CustomerLogin.h:
#interface CustomerLogin : NSObject
#property (nonatomic) NSArray *customerPromotions;
#property (strong, nonatomic) NSNumber *customerStatus;
#property (strong, nonatomic) NSString *customerVoucherIcon;
#property (strong, nonatomic) NSString *customerVoucherText;
#property (strong, nonatomic) NSString *customerVoucherTitle;
#property (strong, nonatomic) NSNumber *errorID;
#property (strong, nonatomic) NSString *errorMessage;
#property (strong, nonatomic) NSNumber *feedbackIndicator;
#property (strong, nonatomic) NSString *feedbackLowerText;
#property (strong, nonatomic) NSString *feedbackTitle;
#property (strong, nonatomic) NSString *hpTopTitle;
#property (strong, nonatomic) NSString *localCurrencySign;
#property (strong, nonatomic) NSString *localCurrencyValue;
#property (strong, nonatomic) NSString *localTime;
#property (strong, nonatomic) NSString *localWeather;
#property (strong, nonatomic) NSString *popUpTopTitle;
#end
This is 'CustomerPromotions`:
#interface CustomerPromotions : NSObject
#property (strong, nonatomic) NSString *bottomTitle;
#property (strong, nonatomic) NSString *iconURL;
#property (strong, nonatomic) NSString *middleText;
#property (strong, nonatomic) NSString *promotionID;
#property (strong, nonatomic) NSNumber *sortOrder;
#property (strong, nonatomic) NSString *topTitle;
#end
This is the mapping:
RKObjectMapping *customerLoginMapping = [RKObjectMapping mappingForClass:[CustomerLogin class]];
[customerLoginMapping addAttributeMappingsFromDictionary:#{ #"CustomerStatus" : #"customerStatus",
#"CustomerVoucherIcon" : #"customerVoucherIcon",
#"CustomerVoucherText" : #"customerVoucherText",
#"CustomerVoucherTitle" : #"customerVoucherTitle",
#"ErrorID" : #"errorID",
#"ErrorMessage" : #"errorMessage",
#"FeedbackIndicator" : #"feedbackIndicator",
#"FeedbackLowerText" : #"feedbackLowerText",
#"FeedbackTitle" : #"feedbackTitle",
#"HPTopTitle" : #"hpTopTitle",
#"LocalCurrencySign" : #"localCurrencySign",
#"LocalCurrencyValue" : #"localCurrencyValue",
#"LocalTime" : #"localTime",
#"LocalWeather" : #"localWeather",
#"PopUpTopTitle" : #"popUpTopTitle" }];
RKObjectMapping *customerPromotionsMapping = [RKObjectMapping mappingForClass:[CustomerPromotions class]];
[customerPromotionsMapping addAttributeMappingsFromDictionary:#{ #"BottomTitle" : #"bottomTitle",
#"IconURL" : #"iconURL",
#"MiddleText" : #"middleText",
#"PromotionID" : #"promotionID",
#"SortOrder" : #"sortOrder",
#"TopTitle" : #"topTitle" }];
[customerLoginMapping addRelationshipMappingWithSourceKeyPath:#"customerPromotions" mapping:customerPromotionsMapping];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:customerLoginMapping
method:RKRequestMethodPOST
pathPattern:#"CustomerLogin"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];
This is the POST request:
NSDictionary *params = #{ #"AppID" : #"1",
#"AppPassword" : #"String content",
#"Password" : #"password",
#"UserName" : #"username" };
[[RKObjectManager sharedManager] postObject:[[CustomerLogin alloc] init]
path:#"CustomerLogin"
parameters:params
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"%#", operation.HTTPRequestOperation.responseString);
NSLog(#"%#", mappingResult.array);
CustomerLogin *customer = [mappingResult.array lastObject];
NSLog(#"%#", customer.customerPromotions);
NSLog(#"%#", customer.hpTopTitle);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"%#", error.localizedDescription);
}];
It just looks like your key name is wrong. You use a source key only, which means the source and destination should match but they don't actually match. Try:
RKRelationshipMapping *relationMapping = [RKRelationshipMapping relationshipMappingFromKeyPath:#"CustomerPromotions" toKeyPath:#"customerPromotions" withMapping:customerPromotionsMapping];
[customerLoginMapping addPropertyMapping:relationMapping];

RestKit not mapping Images from JSON

I'm not able to map the Images from my JSON response correctly, and I can't figure out why.
Here is error: "W restkit.object_mapping:RKObjectMappingOperation.m:244 Failed transformation of value at keyPath 'images'. No strategy for transforming from '__NSArrayM' to 'Images'"
Here is JSON:
{
"timestamp": "2013-05-10T03:09:39Z",
"feed": [{
"headline": "Head text",
"links": {
"api": {
"news": {
"href": "http://api.website.com/v1/91"
},
"self": {
"href": "http://api.website.com/v1/91"
}
},
"web": {
"href": "http://website.com/the/story"
},
"mobile": {
"href": "http://m.website.com/wireless/story?storyId=9254113"
}
},
"source": "Associated Press",
"description": "Description text.",
"images": [{
"height": 324,
"alt": "",
"width": 576,
"name": "Name text",
"caption": "Caption text.",
"url": "http://a.website.com/media/2013/0508.jpg"
}],
Feed.h
#property (nonatomic, strong) Links *links;
#property (nonatomic, strong) Images *images;
#property (nonatomic, strong) Video *video;
#property (nonatomic, strong) NSString *headline;
#property (nonatomic, strong) NSString *source;
#property (nonatomic, strong) NSDate *published;
#property (nonatomic, strong) NSString *description;
#property (nonatomic, strong) NSString *premium;
+ (RKObjectMapping *) mapping;
Feed.m
+ (RKObjectMapping *)mapping {
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[self class] usingBlock:^(RKObjectMapping *mapping) {
[mapping mapKeyPathsToAttributes:
#"headline", #"headline",
#"source", #"source",
#"published", #"published",
#"description", #"description",
#"premium", #"premium",
nil];
[mapping hasOne:#"links" withMapping:[Links mapping]];
[mapping hasOne:#"images" withMapping:[Images mapping]];
//[mapping hasMany:#"images" withMapping:[Images mapping]];
[mapping hasOne:#"video" withMapping:[Video mapping]];
}];
return objectMapping;
}
Images.h
#property (nonatomic, strong) NSNumber *height;
#property (nonatomic, strong) NSNumber *width;
#property (nonatomic, strong) NSString *caption;
#property (nonatomic, strong) NSURL *url;
+ (RKObjectMapping *) mapping;
Images.m
+ (RKObjectMapping *)mapping {
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[self class] usingBlock:^(RKObjectMapping *mapping) {
[mapping mapKeyPathsToAttributes:
#"height", #"height",
#"width", #"width",
#"caption", #"caption",
#"url", #"url",
nil];
}];
return objectMapping;
}
Everything else is mapping correctly except images. I don't know if it has to do with it being an Array but it only having one result, so its not necessarily an array? And if its not, then how I would write that... I'm just not totally clear on why its not mapping.
As you can see I tried both hasMany: and hasOne: mapping and neither worked, I got the same error.
I tried using NSLog(#"url image: %#", feedLocal.images.url);' but get(null). Even though I thought it would work becauseNSLog(#"href web: %#", feedLocal.links.web.href);` works perfectly for my links href.
Any help would be greatly appreciated, thanks so much!
In Feed.h you need to change your images property to be:
#property (nonatomic, strong) NSArray *images;
And you should set the mapping to hasMany:.

Resources