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:.
Related
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...
I am confused completely to parse this kind of response in restkit. I am using this link but i am not able to understand how to parse this response.Any help would be appreciated.
“groups”: {
"group1": [
{
"email": "blake#restkit.org",
"favorite_animal": "Monkey"
},
{
"email": "slake#restkit.org",
"favorite_animal": "Donkey"
}
],
"group2": [
{
"email": "sarah#restkit.org",
"favorite_animal": "Cat"
},
{
"email": "varah#restkit.org",
"favorite_animal": "Cow"
}
]
}
I am Using Below mapping.
#interface GroupResponse : NSObject
#property (nonatomic, strong) NSArray *Groups;
+ (RKObjectMapping *)mapping;
#end
#implementation GroupResponse
+ (RKObjectMapping *)mapping {
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[self class]];
[objectMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#“groups” toKeyPath:#“Groups” withMapping:[GroupData mapping]]];
return objectMapping;
}
#end
#interface GroupData : NSObject
#property (nonatomic, strong) NSString *groupName;
#property (nonatomic, strong) NSString *arrPersons;
+ (RKObjectMapping *)mapping;
#end
#implementation GroupData
+ (RKObjectMapping *)mapping {
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[self class]];
objectMapping.forceCollectionMapping = YES;
[objectMapping addAttributeMappingFromKeyOfRepresentationToAttribute:#"groupName"];
[objectMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#“(groupName)” toKeyPath:#"arrPersons" withMapping:[Person mapping]]];
return objectMapping;
}
#end
#interface Person : NSObject
#property (nonatomic, strong) NSString *email;
#property (nonatomic, strong) NSString *favAnimal;
+ (RKObjectMapping *) mapping;
#end
#implementation Person
+ (RKObjectMapping *)mapping {
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:[self class]];
[objectMapping addAttributeMappingsFromDictionary:#{#"email" : #"email",
#"favorite_animal" : #"favAnimal"}];
return objectMapping;
}
#end
Everytime arrPersons is nil. How to do proper mapping in this case.
This attribute:
#property (nonatomic, strong) NSString *arrPersons;
should actually be a mutable array, not a string type:
#property (nonatomic, strong) NSMutableArray *arrPersons;
because the nested JSON array can't be converted into a string and your mapping indicates that it should be processed into an array of Person objects.
Hi I am getting parsed nested JSON, which has many levels. I am able to get at first level value.
How could i use same model class to fetch all nested JSON values using recursion.
My JSON is -
{
"message": "Ok",
"STATUS_CODE": "200",
"REQUEST": {
"userid": "12436124",
"command": "GETCATEGORY"
},
"RESPONSE": {
"Category": [
{
"type": "Tag",
"categoryId": 11,
"name": "Electronics",
"catIconLeft": "",
"catIconRight": "",
"parentId": 0,
"Category": [
{
"type": "Category",
"categoryId": 84,
"name": "Mobile Accessories",
"parentId": 1,
"catIconLeft": "",
"catIconRight": "",
"Category": [
{
"type": "Product",
"categoryId": 90,
"name": "Headsets",
"catIconLeft": "",
"catIconRight": "",
"parentId": 9
},
<----so on------>
The complete Parsed JSON LINK
My Code for parsing-
-(void)call_CategoryListData{
[params setObject:#"command" forKey:#"GETCATEGORY"];
[params setObject:#"userid" forKey:#"12436124"];
[serverCall actionmethod:Fake_Category parameters:params onComplete:^(NSMutableDictionary* results){
if ([results isKindOfClass:[NSDictionary class]] || [results isKindOfClass:[NSMutableDictionary class]]){
//DDLogVerbose(#"\n\n\n\n\nResult----->%#",results);
NSMutableDictionary*responseDic=[results objectForKey:#"RESPONSE"];
NSMutableArray*catArray=[responseDic objectForKey:#"Category"];
for (NSMutableDictionary *dic in catArray) {
NSMutableArray* tmp = [dic objectForKey:#"Category"];
if (tmp) {
MyCategory *cat = [[MyCategory alloc] init];
cat.type = dic[#"type"];
cat.categoryId = dic[#"categoryId"];
if ([cat.type isEqualToString:#"Tag"]) {
cat.name = dic[#"name"];
cat.categoryId = dic[#"categoryId"];
[CatTag addObject:cat.name];
[CatID addObject:cat.categoryId];
<---------so on --------------->
NSLog(#"New Objects--->%#\n\n----->%#",CatTag,CatID);
}
}
}
}
}
onError:^(NSError *error) {
// handle error here
}];
}
My Model Class-
#interface MyCategory : NSObject
#property (nonatomic, strong) NSString *type;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *categoryId;
#property(nonatomic,strong) NSString *catIconLeft;
#property (nonatomic,strong) NSString *catIconRight;
#property (nonatomic,strong) NSString *parentId;
#property (nonatomic, strong) MyCategory*Category;
MyCategory.h file
#interface MyCategory : NSObject
#property (nonatomic, strong) NSString *type;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *categoryId;
#property (nonatomic, strong) NSString *catIconLeft;
#property (nonatomic, strong) NSString *catIconRight;
#property (nonatomic, strong) NSString *parentId;
#property (nonatomic, strong) NSArray *categories;
- (id)initWithRootDictionary:(NSDictionary *)dictionary;
#end
MyCategory.m hile
#implementation
- (id)initWithRootDictionary:(NSDictionary *)dictionary
{
self = [super init];
self.type = dictionary[#"type"];
self.name = dictionary[#"name"];
self.categoryId = dictionary[#"categoryId"];
self.catIconLeft = dictionary[#"catIconLeft"];
self.catIconRight = dictionary[#"catIconRight"];
self.parentId = dictionary[#"parentId"];
if (dictionary[#"category"]) {
NSMutableArray *categories = [NSMutableArray new];
for (NSDictionary *cat in dictionary[#"category"]) {
MyCategory *category = [[MyCategory alloc] initWithRootDictionary:cat];
[categories addObject:category];
}
self.categories = categories;
}
return self;
}
#end
//...
-(void)call_CategoryListData
{
//...
NSMutableDictionary * responseDic = [results objectForKey:#"RESPONSE"];
NSMutableArray * catArray = [responseDic objectForKey:#"Category"];
NSMutableArray *result = [NSMutableArray new];
for (NSDictionary *categoryDic in catArray) {
MyCategory *category = [[MyCategory alloc] initWithRootDictionary:categoryDic];
[result addObject:category];
}
// Do something with result
}
This is a fast written code directly in this editor without any IDE, so possible some syntax errors :)
Here is my JSON
{
"pages": 8,
"salads": [
{
"id": "392",
"img": "http://salatiki.com.ua/images/mini/20120114_285.jpg",
"ingredCount": 5,
"ingredients": "картофель, свекла, салат, яйцо, сливки",
"name": "Шведский картофельный",
"rating": 4
},
.......
]
}
I got "pages", but my "salads" is nil (see log).
My NSManagedObjects
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#class SSaladsBody;
#interface SSaladPage : NSManagedObject
#property (nonatomic, retain) NSNumber * sPages;
#property (nonatomic, retain) SSaladsBody *salads;
#end
for key "salads"
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#interface SSaladsBody : NSManagedObject
#property (nonatomic, retain) NSNumber * sId;
#property (nonatomic, retain) NSString * sImage;
#property (nonatomic, retain) NSString * sName;
#property (nonatomic, retain) NSNumber * sRating;
#property (nonatomic, retain) NSString * sIngredients;
#property (nonatomic, retain) NSNumber * sIngredientsCount;
#end
in my add delegate
RKEntityMapping *saladPageMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([SSaladPage class]) inManagedObjectStore:managedObjectStore];
[saladPageMapping addAttributeMappingsFromDictionary:#{ #"pages" : #"sPages", }];
saladPageMapping.identificationAttributes = #[#"sPages"];
RKEntityMapping *saladsBodyMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([SSaladsBody class]) inManagedObjectStore:managedObjectStore];
[saladsBodyMapping addAttributeMappingsFromDictionary:#{ #"id" : #"sId",
#"img" : #"sImage",
#"name" : #"sName",
#"rating" : #"sRating",
#"ingredients" : #"sIngredients",
#"ingredCount" : #"sIngredientsCount" }];
saladsBodyMapping.identificationAttributes = #[#"sId"];
[saladPageMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"salads"
toKeyPath:#"salads"
withMapping:saladsBodyMapping]];
RKResponseDescriptor *saladPageDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:saladPageMapping
method:RKRequestMethodGET
pathPattern:nil
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[manager addResponseDescriptorsFromArray: #[saladPageDescriptor]];
[[RKObjectManager sharedManager] getObjectsAtPath:#"api/get.php?getByCat=1&page=1" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Mapping salads OK! %#", mappingResult.array);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#",error);
}];
and log
2014-11-04 23:57:49.641 Salatiki[10213:f03] I restkit.network:RKObjectRequestOperation.m:250 GET 'http://salatiki.com.ua/api/get.php?getByCat=1&page=1' (200 OK / 1 objects) [request=0.0989s mapping=0.0117s total=0.1613s]
2014-11-04 23:57:49.641 Salatiki[10213:607] Mapping salads OK! (
"<SSaladPage: 0x7b03b970> (entity: SSaladPage; id: 0x7b267d90 <x-coredata://8CC2FD2A-9D05-4863-99AA-30B318EEC57C/SSaladPage/p42> ; data: {\n sPages = 8;\n salads = nil;\n})"
)
what i'm doing wrong? I try to add one more responseDeskriptor, for "salads" it work's but he put array in to main {}; not to "salads" = []; Thank you.
The property
#property (nonatomic, retain) SSaladsBody *salads;
should actually be a relationship, so it should be NSSet, not SSaladsBody.
Other than that, things look ok. If you still have issues you should turn on trace logging and see what processing is done around the relationship contents.
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];