I am trying to get RestKit to use some sideloaded associations in my JSON, the JSON looks like the following:
{
"companies": [
{
"id": 1,
"name": "420...",
"street": "420 Kush St.",
"city": "Seattle",
"state": "WA",
"zip_code": "12345"
}
],
"user": {
"id": 1,
"email": "test#example.com",
"token": "1234567890",
"company_id": 1
}
}
I am not using the CoreData integration and need the company attribute of my user to fill in with the company found in the "companies" key of the above JSON. My current user mapping looks like:
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[GBUser class]];
[mapping addAttributeMappingsFromDictionary:#{
#"id": #"userId",
#"email": #"email"
}];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
return [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:#"/api/v0/me" keyPath:#"user" statusCodes:statusCodes];
The simplest option is to write a couple of lines of code in the success block to associate the objects in the mapping result. You would use 2 response descriptors to map the users and companies separately and then combine them after the mapping has completed.
Related
I am saving objects in core data which is in the below format.
{
"propertyId": 1,
"name": "some_name_1",
"userName": "some_email_1"
},
{
"propertyId": 1,
"name": "some_name_2",
"userName": "some_email_2"
},
{
"propertyId": 2,
"name": "some_name_3",
"userName": "some_email_3"
},
{
"propertyId": 2,
"name": "some_name_4",
"userName": "some_email_4"
},
{
"propertyId": 3,
"name": "some_name_5",
"userName": "some_email_5"
},
{
"propertyId": 3,
"name": "some_name6_",
"userName": "some_email_6"
}
Now, the problem is that only the last object from the group of the same propertyId is getting saved in the Core Data.
This is the code I got from the previous developer. Mapping is used to store data.
RKEntityMapping *rkEntityMapping = [RKEntityMapping mappingForEntityForName:#"PropertyAssignee" inManagedObjectStore:self.managedObjectStore];
rkEntityMapping.identificationAttributes = #[#"propertyId"];
[rkEntityMapping addAttributeMappingsFromDictionary:#{
#"propertyId": #"propertyId",
#"name": #"name",
#"userName": #"userName"}];
[rkEntityMapping addConnectionForRelationship:#"property" connectedBy:#{#"propertyId": #"objId"}];
RKObjectMapping *syncMapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
[syncMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"propertyAssgineeResponse" toKeyPath:#"propertyAssgineeResponse" withMapping:propertAssigneeMapping]];
RKResponseDescriptor *responseDescriptorProperties = [RKResponseDescriptor responseDescriptorWithMapping:syncMapping method:RKRequestMethodAny pathPattern:#"/api/sync" keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]];
[self.objectManager addResponseDescriptor:responseDescriptorProperties];
I am not getting any clue of why this is happening.
I am having difficulty mapping a object in Restkit which is nested. The response is as follows:
{
"status": "SUCCESS",
"message": "Newsfeeds loaded successfully",
"links": {
"self": ""
},
"newsfeeds": [
{
"type": "post",
"content": {
"id": "39ff4ea6-71d4-4d9c-872b-94d878ec54fd",
"owner_id": "75c72102-d7dc-44c6-bb62-c48b487897c4",
"owner_firstname": "Goran",
"owner_lastname": "Don",
"owner_profilephoto": "88f5930b-e779-47ac-86b7-4f31cd0d82aa.jpg",
"contents": [
{
"type": "text",
"content": "Being the richest man in the cemetery doesn't matter to me. Going to bed at night saying we've done something wonderful, that's what matters to me.\n Sometimes when you innovate, you make mistakes. It is best to admit them quickly, and get on with improving your other innovations"
},
{
"type": "url",
"content": {
"title": "Beautiful landscape view Of New Zealand and Australia is available here",
"position": "landscape",
"url": "39ff4ea6-71d4-4d9c-872b-94d878ec54fd/Img_62151fbd-119f-4a84-91a9-f37bfa6293db.jpg"
}
}
],
"postdatetime": "May 18 2016 12:18:54.442 UTC",
"selfLike": false,
"likes": 0,
"comments": 0,
"starred": "false"
}
},
{
"type": "post",
"content": {
"id": "7117d132-1811-4ac7-bfaf-bbb397eefb10",
"owner_id": "75c72102-d7dc-44c6-bb62-c48b487897c4",
"owner_firstname": "Goran",
"owner_lastname": "Don",
"owner_profilephoto": "88f5930b-e779-47ac-86b7-4f31cd0d82aa.jpg",
"contents": [
{
"type": "text",
"content": "Hi this is a test"
}
],
"postdatetime": "May 18 2016 11:42:24.978 UTC",
"selfLike": false,
"likes": 0,
"comments": 0,
"starred": "false"
}
},
{
"type": "post",
"content": {
"id": "fbeb20cf-c87b-40db-9753-9fa32aac921a",
"owner_id": "75c72102-d7dc-44c6-bb62-c48b487897c4",
"owner_firstname": "Goran",
"owner_lastname": "Don",
"owner_profilephoto": "88f5930b-e779-47ac-86b7-4f31cd0d82aa.jpg",
"contents": [
{
"type": "url",
"content": {
"title": "",
"position": "potrait",
"url": "fbeb20cf-c87b-40db-9753-9fa32aac921a/Img_23771f1c-bb22-4335-ae3f-4e83d97c5c3c.jpg"
}
},
{
"type": "url",
"content": {
"title": "",
"position": "landscape",
"url": "fbeb20cf-c87b-40db-9753-9fa32aac921a/Img_a77e8349-b531-4d9d-944e-88971298c6fa.jpg"
}
}
],
"postdatetime": "May 18 2016 07:39:07.937 UTC",
"selfLike": true,
"likes": 1,
"comments": 0,
"starred": "false"
}
},
{
"type": "post",
"content": {
"id": "71e005a1-71ec-4131-8131-bfd38337ec6a",
"owner_id": "75c72102-d7dc-44c6-bb62-c48b487897c4",
"owner_firstname": "Goran",
"owner_lastname": "Don",
"owner_profilephoto": "88f5930b-e779-47ac-86b7-4f31cd0d82aa.jpg",
"contents": [
{
"type": "url",
"content": {
"title": "",
"position": "potrait",
"url": "post/71e005a1-71ec-4131-8131-bfd38337ec6a/Img_600f6fd0-14f9-4bf3-af6e-f36b7ffedbc6.jpg"
}
}
],
"postdatetime": "May 18 2016 07:27:53.278 UTC",
"selfLike": false,
"likes": 0,
"comments": 0,
"starred": "false"
}
}
]
}
From the above, need to reach "content" within "contents" array. "content" sometimes return string and sometimes dictionary. I am trying to map as follows:
RKObjectMapping * newsFeedMappingObject = [RKObjectMapping mappingForClass:[NewsFeed class]];
[newsFeedMappingObject addAttributeMappingsFromDictionary:#{#"type" : #"type",}];
RKObjectMapping * responseMappingObject = [RKObjectMapping mappingForClass:[ResponseMessage class]];
[responseMappingObject addAttributeMappingsFromDictionary:#{uStatus: #"status",uMessage: #"message",}];
[responseMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"newsfeeds"
toKeyPath:#"newsfeeds"
withMapping:newsFeedMappingObject]];
RKObjectMapping * contentMappingObject = [RKObjectMapping mappingForClass:[Content class]];
[contentMappingObject addAttributeMappingsFromDictionary:#{#"id": #"contentId"}];
[newsFeedMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"content"
toKeyPath:#"cont"
withMapping:contentMappingObject]];
RKObjectMapping * postContentMappingObject = [RKObjectMapping mappingForClass:[PostContent class]];
[postContentMappingObject addAttributeMappingsFromDictionary:#{#"type": #"type",}];
[contentMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"contents"
toKeyPath:#"contents"
withMapping:postContentMappingObject]];
RKObjectMapping * postMappingObject = [RKObjectMapping mappingForClass:[Post class]];
[postMappingObject addAttributeMappingsFromDictionary:#{#"title":#"title"}];
[postContentMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"content"
toKeyPath:#"post"
withMapping:postMappingObject]];
When I run it the app crashes with log as:** * Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0x7fa302826d30> valueForUndefinedKey:]: this class is not key value coding-compliant for the key title.'
Trying my hands on dynamic mapping. But I think I'm doing it wrong:
RKObjectMapping * newsFeedMappingObject = [RKObjectMapping mappingForClass:[NewsFeed class]];
[newsFeedMappingObject addAttributeMappingsFromDictionary:#{
#"type" : #"type",
}];
RKObjectMapping * responseMappingObject = [RKObjectMapping mappingForClass:[ResponseMessage class]];
[responseMappingObject addAttributeMappingsFromDictionary:#{
uStatus: #"status",
uMessage: #"message",
}];
[responseMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"newsfeeds"
toKeyPath:#"newsfeeds"
withMapping:newsFeedMappingObject]];
RKObjectMapping * contentMappingObject = [RKObjectMapping mappingForClass:[Content class]];
[contentMappingObject addAttributeMappingsFromDictionary:#{
#"id": #"contentId",
}];
[newsFeedMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"content"
toKeyPath:#"cont"
withMapping:contentMappingObject]];
RKObjectMapping * postContentMappingObject = [RKObjectMapping mappingForClass:[PostContent class]];
[postContentMappingObject addAttributeMappingsFromDictionary:#{
#"type": #"type",
}];
[contentMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"contents"
toKeyPath:#"contents"
withMapping:postContentMappingObject]];
RKObjectMapping * postMappingObject = [RKObjectMapping mappingForClass:[Post class]];
[postMappingObject addAttributeMappingsFromDictionary:#{
#"title" : #"title"
}];
RKDynamicMapping* dynamicMapping = [RKDynamicMapping new];
[postMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"post" toKeyPath:#"content" withMapping:dynamicMapping]];
// Connect a response descriptor for our dynamic mapping
RKResponseDescriptor *dynamicResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:dynamicMapping method:RKRequestMethodAny pathPattern:nil keyPath:#"content" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:dynamicResponseDescriptor];
// Option 2: Configure the dynamic mapping via a block
[dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {
if ([[representation valueForKey:#"content"] isKindOfClass:[NSDictionary class]]) {
return postMappingObject;
}
return nil;
}];
[postContentMappingObject addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"content"
toKeyPath:#"post"
withMapping:postMappingObject]];
NSString *urlString = [NSString stringWithFormat:#"%#%#%#&userId=%#&startDate=%#&count=%d&scanForward=%#",uServiceUrl,uGetNewsFeedsRequest,accountId,userId,startDate,count,isForward];
NSString* encodedUrl = [urlString stringByAddingPercentEncodingWithAllowedCharacters:
[NSCharacterSet URLQueryAllowedCharacterSet]];
NSURL *getNewsRequestUrl = [NSURL URLWithString:encodedUrl];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMappingObject method:RKRequestMethodAny pathPattern:nil keyPath:#"" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self getWithUrlString:getNewsRequestUrl withMappingObject:responseMappingObject andResponseDescriptors:#[responseDescriptor, dynamicResponseDescriptor] withSuccess:successBlock withFail:failBlock];
You need to change postMappingObject to be an instance of RKDynamicMapping which checks the data that it's provided with to see what it is and returns an appropriate mapping that will actually be used to process that data. The check is to determine if the payload is a string or a dictionary.
the json api has a list of posts, and each post has a list of users that like this post.
post, user each has an entity in core data.
how RestKit do object mapping.
{
posts:[
{
"postid": 1,
"posttext": "post1",
"likeusers":[
{
"uid": 1,
"username": "user1"
},
{
"uid": 2,
"username": "user2"
}
]
},
{
"postid": 2,
"posttext": "post2",
"likeusers":[
{
"uid": 1,
"username": "user1"
},
{
"uid": 2,
"username": "user2"
}
]
}
]
}
Here is how to do the mapping:
// User mapping
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:#"User"
inManagedObjectStore:yourManagedObjectStore];
userMapping.identificationAttributes = #[#"userID"];
[userMapping addAttributeMappingsFromDictionary:#{
#"uid": #"userID",
#"username": #"username",
}];
// Post mapping
RKEntityMapping *postMapping = [RKEntityMapping mappingForEntityForName:#"Post"
inManagedObjectStore:yourManagedObjectStore];
postMapping.identificationAttributes = #[#"postID"];
[postMapping addAttributeMappingsFromDictionary:#{
#"postid": #"postID",
#"posttext": #"postText",
}];
[postMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"likeusers"
toKeyPath:#"likeUsers" withMapping:userMapping]];
Hope it helps.
I have two tables say Articles and Authors. Each Article have many authors and same author can be come in multiple Articles. My Json response is looks like this.
{
"Articles": [
{
"artName": "ABC",
"artId": "1",
"Authors": [
{
"autName": "James",
"autId": "200",
"email": "james#xyz.com"
},
{
"autName": "Mark",
"autId": "201",
"email": "mark#xyz.com"
},
{
"autName": "Robert",
"autId": "202",
"email": "robert#xyz.com"
}
]
},
{
"artName": "BCD",
"artId": "2",
"Authors": [
{
"autName": "James",
"autId": "200",
"email": "james#xyz.com"
},
{
"autName": "Ben",
"autId": "204",
"email": "ben#xyz.com"
},
{
"autName": "Rayon",
"autId": "205",
"email": "rayon#xyz.com"
}
]
}
]
}
Mapping:
RKObjectManager *manager = [[RestKit sharedDataManager] objectManager];
RKEntityMapping *ArticleMapping = [RKEntityMapping mappingForEntityForName:#"Articles" inManagedObjectStore:manager.managedObjectStore];
ArticleMaping.identificationAttributes = #[#"artId"];
ArticleMaping addAttributeMappingsFromDictionary:#{
#"artId": #"artId",
}];
RKEntityMapping *AuthorMapping = [RKEntityMapping mappingForEntityForName:#"Authors" inManagedObjectStore:manager.managedObjectStore];
AuthorMapping.identificationAttributes = #[#"autId"];
AuthorMapping addAttributeMappingsFromDictionary:#{
#"autId": #"autId",
#"autName" : #"autName",
#"email" : #"email"
}];
[ArticleMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"Authors" toKeyPath:#"Authors" withMapping:AuthorMapping]];
I have made a relationship for Articles and Authors. It is mapping correctly, but when i try to fetch the authors for "artName" ABC. i am getting only 2 authors. but when i try to fetch data for "artName" BCD. i am getting 3 authors. when checked in DB, relationship key for record "James" is overwritten by record of BCD.
How can i access all the authors for both the articles.
Note: I am using Restkit 0.20
Thank you
The relationship between the 2 objects needs to be many to many or the new assignment will explicitly break the old assignment.
When you create your RKRelationshipMapping, ensure that you set the assignmentPolicy to RKUnionAssignmentPolicy. The default is RKSetAssignmentPolicy which could be removing the existing setting.
I'm trying to parse github's gist api response with RestKit. Here is a fragment of json:
{
"url": "https://api.github.com/gists/6004248",
...
"html_url": "https://gist.github.com/6004248",
"files": {
"ApplicationContext.h": {
"filename": "ApplicationContext.h",
"type": "text/plain",
"language": "Objective-C",
"raw_url": "https://gist.github.com/raw/6004248/4531c7534585b273c55ca71ce9020418b7ed271b/ApplicationContext.h",
"size": 481
},
"ApplicationContext.m": {
"filename": "ApplicationContext.m",
"type": "text/plain",
"language": "Objective-C",
"raw_url": "https://gist.github.com/raw/6004248/27a3881f9c5adde700b75199076a5ce259d0b568/ApplicationContext.m",
"size": 542
}
},
...
"user": {
...
},
"comments_url": "https://api.github.com/gists/6004248/comments"
},
Everything works fine, but i have problem with a files relationship. Here is a fragment of code responsible for files:
RKObjectMapping *gistMapping = [RKObjectMapping mappingForClass:[MBGist class]];
[gistMapping addAttributeMappingsFromDictionary: #{#"url": #"url", #"html_url": #"htmlUrl", #"description": #"description"}];
RKObjectMapping *fileMapping = [RKObjectMapping mappingForClass:[MBFile class]];
[fileMapping addAttributeMappingsFromDictionary:#{#"filename": #"filename", #"language": #"language", #"type":#"type"}];
[gistMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"files" toKeyPath:#"files" withMapping:fileMapping]];
but I have empty files arrays in my MBGist class objects.
Can anybody help me with it?
Best Regards,
MichaĆ
Please refer to Handling Dynamic Nesting Attributes section in Restkit ObjectMapping