Traverse upwards in JSON when mapping using RestKit 0.20 - ios

I have the following JSON structure:
{
"category": "MyCategory"
"objects": [
{ "id": 1, "name": "A" },
{ "id": 2, "name": "B" },
{ "id": 3, "name": "C" }
]
}
I'm mapping each object to a separate Core Data entity like this:
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:#"Object" inManagedObjectStore:manager.managedObjectStore];
mapping.identificationAttributes = #[ #"id" ];
[mapping addAttributeMappingsFromDictionary:#{ #"name": #"name" }];
How do I configure the mapping to store their shared category on each object?
The thing I would like is to be able to traverse upwards in the JSON like this:
[mapping addAttributeMappingsFromDictionary:#{ #"name": #"name", #"PARENT.category": #"category" }];

As of now (RestKit 0.20.1), there is no way to do this by using the mapping engine.
FUTURE
There is a new metadata feature under development making it possible to access the parent object:
[mapping addAttributeMappingsFromDictionary:#{ #"name": #"name", #"#metadata.parentObject.category": #"category" }];
PRESENT
I'm modifying my deserialized response using willMapDeserializedResponseBlock. I've added a category on RKObjectManager to make it easy to modify the response:
https://gist.github.com/gunnarblom/5677324

Related

RKObjectMapper not mapping array of dictionaries

I am using RKObjectMapping to map the response JSON to my predefined model but I am facing some issues when I try to map array of dictionaries.
JSON Response :
{
total: 274,
per_page: 10,
current_page: 1,
last_page: 28,
prev_page_url: null,
from: 1,
to: 10,
data: - [
- {
_id: "someid",
legacy_id: someid,
username: "awesome",
legacy_account_id: 12326,
brand_name: "Awesome",
last_review_ids: - [
],
category_profession_ids: - [
],
score_award: - {
},
score_award_one: - {
},
photos: - [
- {
_id: "someid"
},
- {
_id: "someanotherid"
}
}
],
enabled_at_utc: "2015-08-04 04:06:26",
published_at_utc: "2016-11-10 11:05:55",
last_activity_at_utc: "2016-04-10 16:17:06",
last_booked_at_utc: "2016-11-15 08:51:31",
last_reviewed_at_utc: "2016-11-08 10:50:13",
created_at_utc: "2015-08-04 04:03:59",
updated_at_utc: "2016-11-16 04:31:10"
},
+ {... },
+ {... },
+ {... },
+ {... },
+ {... },
+ {... },
+ {... },
+ {... },
+ {... }
],
client_version: "1"
}
And for mapping above response I have added below mapping methods
+ (RKObjectMapping *)professionalMapping{
// setup object mappings
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[ProfessionalModel class]];
[mapping addAttributeMappingsFromArray:baseModelMapping];
[mapping addAttributeMappingsFromArray:#[#"username", #"first_name", #"last_name", #"brand_name", #"profile_url", #"image", #"account_id", #"service_rules", #"lead_time_cancellation", #"faqs", #"work_experience", #"education", #"accolades", #"phone_no", #"contact_no", #"contact_no_hide", #"email", #"email_hide", #"website", #"website_hide", #"facebook", #"twitter", #"instagram", #"service_location", #"service_location_hide", #"housecall", #"housecall_charges", #"housecall_charges_display", #"published_at", #"enabled_at", #"created_at", #"updated_at", #"is_registered", #"id_no", #"id_full_name", #"id_front_image", #"id_back_image", #"id_address1", #"id_address2", #"id_postal_code", #"id_city", #"id_state", #"id_country", #"service_count", #"review_count", #"booking_count", #"share_url", #"distance", #"distance_unit", #"distance_display", #"neighbourhood", #"photo_count", #"review_photo_count", #"work_photo_count", #"location_photo_count", #"location_type", #"is_bookmarked", #"bookmark_id",#"user_id",#"is_followed",#"menus_display", #"payout_outstanding_display", #"payout_complete_display", #"payout_total_display", #"payout_outstanding"]];
[mapping addAttributeMappingsFromArray:#[#"rating_overall", #"rating_accuracy", #"rating_communication", #"rating_skill", #"rating_value", #"rating_attitude", #"rating_cleanliness", #"rating_environment"]]; // Rating attr
[mapping addAttributeMappingsFromArray:#[#"rating_overall_stats", #"rating_communication_stats", #"rating_attitude_stats", #"rating_cleanliness_stats", #"rating_environment_stats", #"rating_service_stats"]];
[mapping addAttributeMappingsFromArray:#[#"bank_id", #"bank_account_holder_name", #"bank_account_no", #"bank_branch_code", #"bank_code"]]; // Payout Method attr
[mapping addAttributeMappingsFromArray:#[#"transaction_fee_count_display",#"transaction_fee_count",#"currency_code",#"is_top_artist",#"top_artist_category_ids"]];
[mapping addAttributeMappingsFromDictionary:#{#"price_new_customer_fee_display": #"price_transacton_fee_display"}];
[mapping addAttributeMappingsFromDictionary:#{#"description": #"description2"}];
[mapping addRelationshipMappingWithSourceKeyPath:#"user" mapping:[self accountMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"country" mapping:[self countryMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"currency" mapping:[self currencyMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"timezone" mapping:[self timezoneMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"service_address" mapping:[self addressMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"service_addresses" mapping:[self addressMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"service_address_display" mapping:[self addressMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"id_home_addr" mapping:[self addressMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"menu" mapping:[self professionMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"photos" mapping:[self photoMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"reviews" mapping:[self bookingCustomerReviewMapping]];
[mapping addRelationshipMappingWithSourceKeyPath:#"last_reviews" mapping:[self bookingCustomerReviewMapping]];//because account (?)
return mapping;
}
+ (RKObjectMapping *)professionalTotalMapping{
RKObjectMapping* professionalMapping = [self professionalMapping];
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[ProfessionalTotalMapping class]];
[mapping addAttributeMappingsFromArray:#[#"total"]];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"data" toKeyPath:#"professional" withMapping:professionalMapping]];
return mapping;
}
But all I get is nil initialised ProfessionalTotalMapping and the code can't even map a single key.
Please let me know whats wrong in my mapping code.
Any help would be much appreciated.
Thanks
Found the solution by not creating 2 separate models.
So now I am parsing the whole response including all those required fields and creating a single model object which has all the data that I need.
Thanks

How to map this object in RESTKit

I have JSON of following kind
{
"Client": {
"FirstName": "String",
"LastName": "String",
"Email": "String",
"Password": "String",
"PhoneNumber": "String",
"Token": "String"
},
"ErrorMessage": "String",
"FriendlyMessage": "String"
}
I know that while mapping if I specify a key path then RestKit matches fields from object specified, in this case Client, to the code I am using for that is as follows
[responseMapping addAttributeMappingsFromDictionary:#{
#"FirstName": #"FirstName",
#"LastName": #"LastName",
#"Email": #"Email",
#"PhoneNumber": #"PhoneNumber",
#"Token": #"Token",
#"Password": #"Password",
#"ErrorMessage": #"ErrorMessage"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping
method:RKRequestMethodPOST
pathPattern:nil
keyPath:#"Client"
statusCodes:[NSIndexSet indexSetWithIndex:200]];
But I have two additional fields to map which aren't under client object. How do I map ErrorMessage and FriendlyMessage fields ?
Generally you wouldn't want to map them into your client object, you would want to map them into some other object. You would usually use a different object and response mapping, where the response mapping uses a different key path.
If for some reason you did want them in the same object then you could look at using the #metadata / #parent to get to the parent (https://github.com/RestKit/RestKit/pull/1435).

How to pass an array in an url query parameter using nsurl in objective-c?

The API need to pass an array in an url query parameter, how to acheive this in iOS?
I only know how to pass a single vaue, like the API below : ?title=Design Milk&id=feed/http://feeds.feedburner.com/design-milk
API sample:
"title": "Design Milk",
"id": "feed/http://feeds.feedburner.com/design-milk",
"categories": [
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
"label": "design"
},
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/weekly",
"label": "weekly"
},
{
"id": "user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/global.must",
"label": "must reads"
}
]
Create a collection and then use NSJSONSerialization to create JSON data representation. Use the resulting data as the POST data.
NSDictionary *parameters = #{
#"title": #"Design Milk",
#"id": #"feed/http://feeds.feedburner.com/design-milk",
#"categories": #[
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/design",
#"label": #"design"
},
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/weekly",
#"label": #"weekly"
},
#{
#"id": #"user/c805fcbf-3acf-4302-a97e-d82f9d7c897f/category/global.must",
#"label": #"must reads"
}
]
};
NSError *error;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dictData options:0 error:&error];

RestKit Dynamic Mapping with heterogeneouse collections and Core Data

I have the following JSON structure which I want to map with RestKit in CoreData:
[
{
"id": 1,
"type": "folder",
"name": "Folder 1",
"children": [
{
"id": 1,
"type": "document",
"name": "Document 1"
},
{
"id": 2,
"type": "folder",
"name": "Folder 2",
"children": [
{
"id" : 2,
"type": "document",
"name": "Document 2"
}
]
}
]
}
]
It's a typical filesystem structure where a folder can contain other folders or documents.
I have two CoreData entities: Folder and Document.
The Folder entity has the following relationships:
Here is my Mapping Code:
RKEntityMapping* foldersMapping = [RKEntityMapping mappingForEntityForName:#"Folder" inManagedObjectStore:managedObjectStore];
foldersMapping.identificationAttributes = #[ #"objectId" ];
[foldersMapping addAttributeMappingsFromDictionary:#{#"id" : #"objectId",
#"name" : #"name"}];
RKEntityMapping* documentsMapping = [RKEntityMapping mappingForEntityForName:#"Document" inManagedObjectStore:managedObjectStore];
documentsMapping.identificationAttributes = #[ #"objectId" ];
[documentsMapping addAttributeMappingsFromDictionary:#{#"id" : #"objectId",
#"name" : #"name"}];
In my dynamic mapping I use the type of the object to decide if it is a document or a folder.
RKDynamicMapping* dynamicMapping = [RKDynamicMapping new];
[dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {
if ([[representation valueForKey:#"type"] isEqualToString:#"Folder"]) {
return foldersMapping;
} else if ([[representation valueForKey:#"type"] isEqualToString:#"Document"]) {
return documentsMapping;
}
return nil;
}];
Now I added the dynamic mapping as relationship mapping to the folder mapping for the property children two times.
[foldersMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"children" toKeyPath:#"children" withMapping:dynamicMapping]];
[foldersMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"children" toKeyPath:#"documents" withMapping:dynamicMapping]];
And here is my Problem: All this works, but I got the following Warnings:
RestKitNesterFolderTestProject[9969:3a03] W
restkit.object_mapping:RKMappingOperation.m:554 WARNING: Failed
mapping nested object: The operation couldn’t be completed. (Cocoa
error 1550.)
I think the Problem is that I doubled the mapping for the relationship children, so RestKit tries to map each child two times, once as Folder and once as Document.
Any help is appreciated.

RestKit Core Data mapping one to many

I am using RestKit to map the following JSON to core data.
This is my model:
this is my methods:
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([User class]) inManagedObjectStore:managedObjectStore];
userMapping.identificationAttributes = #[#"id"];
[userMapping addAttributeMappingsFromDictionary:#{
#"birthday":#"birthday",
#"email":#"email",
#"facebook_token":#"facebook_token",
#"first_name":#"first_name",
#"gender":#"gender",
#"interested_in":#"interested_in",
#"last_name":#"last_name",
#"password":#"password",
#"m8_status":#"m8_status",
#"status":#"status",
#"languages": #"languages",
#"hometown":#"hometown",
#"location":#"location",
#"avatar_url":#"avatar_url",
#"mood":#"mood"
}];
RKEntityMapping *findUserMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([FindUser class]) inManagedObjectStore:managedObjectStore];
findUserMapping.identificationAttributes = #[#"id"];
[findUserMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"users" toKeyPath:#"users" withMapping:userMapping]];
[manager addResponseDescriptorsFromArray:#[
[RKResponseDescriptor responseDescriptorWithMapping:findUserMapping
pathPattern:#"/v1/users"
keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]
]];
This is getting objects from example JSON:
{
"users": [
{
"avatar_url": null,
"birthday": "04/11/1984",
"email": "antonina.duminskaya#wildermancruickshank.co.uk", "first_name": "Antonina",
"gender": "female",
"hometown": null,
"id": "5264ee384d61632c4b2f0000",
"interested_in": [
"male",
"female" ],
"languages": [], "last_name": "Duminskaya", "location": null, "m8_status": null,
"mood": null,
"status": null
} ]
}
here:
[objectManager getObjectsAtPath:#"/v1/users" parameters:#{#"session_id":session.id} success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
FindUser *findUsers = [[self.fetchedFindUsersResultsController fetchedObjects] lastObject];
NSLog(#"%#", findUsers.users);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
I have message in log:
Relationship 'users' fault on managed object (0x8e964a0) <FindUser: 0x8e964a0> (entity: FindUser; id: 0x8da0790 <x-coredata://083BB731-FDD7-4A35-A174-724F50862A02/FindUser/p1> ; data: {
id = nil;
users = "<relationship fault: 0x8deb260 'users'>";
})
And In mappingResults I have all results about json
Core Data is representing the relationship initially as fault saving memory by not loading all the object graph at once.
https://developer.apple.com/library/ios/documentation/cocoa/conceptual/CoreData/Articles/cdFaultingUniquing.html
Also, do not use the reserved word 'id' as the Restkit identification attribute for your managed objects. Try using findUserId and userId and update your mappings accordingly.

Resources