I really don't understand why I have an error :/
Can someone look at it ?
Json file :
{
"total_count": 3,
"incomplete_results": false,
"winners": [
{
"windate": "2015-05-26 17:11:30.0",
"gift": "foo",
"email": "foo",
"giftack": "foo",
"lastname": "foo",
"gender": "foo",
"firstname": "foo",
"updategiftdate":null
}
],
"nbWinners": 3
}
Mapping file :
//Winner List Mapping
RKEntityMapping *winnerListMapping =
[RKEntityMapping mappingForEntityForName:#"WinnerList"
inManagedObjectStore:managedObjectStore];
winnerListMapping.identificationAttributes = #[#"nbWinners"];
[winnerListMapping addAttributeMappingsFromDictionary:#{
#"total_count" : #"totalCount",
#"incomplete_results" : #"incompleteResults",
#"nbWinners" : #"nbWinners" }];
//Winner Mapping
RKEntityMapping *winnerMapping =
[RKEntityMapping mappingForEntityForName:#"Winner"
inManagedObjectStore:managedObjectStore];
winnerMapping.identificationAttributes = #[#"winDate"];
[winnerMapping addAttributeMappingsFromArray:#[
#"windate", #"gift", #"email", #"giftack", #"lastname", #"gender", #"firstname", #"updategiftdate"]];
//Link Winner to WinnerList
[winnerListMapping addPropertyMapping:
[RKRelationshipMapping relationshipMappingFromKeyPath:#"winners"
toKeyPath:#"winners"
withMapping:winnerMapping]];
//Run Mapping
RKResponseDescriptor *winnerListResponseDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:winnerListMapping
method:RKRequestMethodGET
pathPattern:#"example.json"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)
];
[objectManager addResponseDescriptor:winnerListResponseDescriptor];
Data Model :
And finally :
2015-09-16 10:13:25.018 iDol Check[26031:954937] 🐛🐛🐛🐛🐛🐛🐛🐛🐛🐛🐛🐛
(
"<WinnerList: 0x7f9d0167f4b0> (entity: WinnerList; id: 0xd0000000000c0000 <x-coredata://7E40E0FD-3677-45EA-9BD1-59F755C05BC5/WinnerList/p3> ; data: {\n incompleteResults = 0;\n nbWinners = 3;\n totalCount = 3;\n winners = \"<relationship fault: 0x7f9d0167afa0 'winners'>\";\n})"
)
Thanks in advance for any help !
I'm betting this is the error.
//Link Winner to WinnerList
[winnerListMapping addPropertyMapping:
[RKRelationshipMapping relationshipMappingFromKeyPath:#"winners"
toKeyPath:#"winners"
withMapping:winnerMapping]];
Specifically the toKeyPath:#"winners" your Winner model do not have a winners attribute.
Related
I have the following entity mapping and descriptor:
RKEntityMapping *responseUserMapping = [APICallUser RKGetUserMappingForManagedObjectStore:self.appDelegate.managedObjectStore];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseUserMapping
[session.objectManager addResponseDescriptor:responseDescriptor];
method:RKRequestMethodPOST
pathPattern:APICallUserCreatePattern
keyPath:#"user"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
Here is the description of the method RKGetUserMappingForManagedObjectStore
+ (RKEntityMapping *) RKGetUserMappingForManagedObjectStore:(RKManagedObjectStore *) store{
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:#"User" inManagedObjectStore:store];
userMapping.identificationAttributes = #[ #"userId" ];
[userMapping addAttributeMappingsFromDictionary:#{
#"id" : #"userId",
#"email" : #"email",
#"firstname" : #"firstName",
#"lastname" : #"lastName",
#"gender" : #"gender",
#"time_zone" : #"timeZone",
#"created_at" : #"createdAt",
#"nickname" : #"pseudo",
#"facebook_id" : #"facebookId",
#"facebook_link_asked_at" : #"lastQueryForFacebookLinkDate",
#"birthday" : #"birthDate",
#"city" : #"city",
#"country" : #"country",
#"sign_in_count" : #"signInCount",
#"facebook_token" : #"facebookToken",
#"facebook_token_expires_at" : #"facebookExpiration",
#"avatar.id" : #"avatarPhotoId"
}];
RKEntityMapping *photoMapping = [APICallPhoto RKGetPhotoMappingForManagedObjectStore:store];
photoMapping.setNilForMissingRelationships = YES;
[userMapping addConnectionForRelationship:#"avatarPhoto" connectedBy:#{#"avatarPhotoId" : #"photoId"}];
//[photoMapping addConnectionForRelationship:#"avatarUsers" connectedBy:#{ #"photoId": #"avatarPhotoId" }];
[userMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"avatar" toKeyPath:#"avatarPhoto" withMapping:photoMapping]];
return userMapping;
}
And the code for the method RKGetPhotoMappingForManagedObjectStore
+ (RKEntityMapping *) RKGetPhotoMappingForManagedObjectStore:(RKManagedObjectStore *) store{
RKEntityMapping *photoMapping = [RKEntityMapping mappingForEntityForName:#"Photo" inManagedObjectStore:store];
photoMapping.identificationAttributes = #[ #"photoId" ];
[photoMapping addAttributeMappingsFromDictionary:#{
#"id" : #"photoId",
#"moment_id" : #"momentId",
#"user_id" : #"userId",
#"title" : #"title",
#"description" : #"photoDescription",
#"file.thumb_url" : #"thumbnailDistURL",
#"file.mini_url" : #"miniDistURL",
#"file.little_url" : #"littleDistURL",
#"file.medium_url" : #"mediumDistURL",
#"file.public_url" : #"originalDistURL"
}];
/*RKEntityMapping *momentMapping = [APICallMoment RKGetMomentMappingForManagedObjectStore:store];
[momentMapping addConnectionForRelationship:#"photos" connectedBy:#{ #"momentId": #"momentId" }];
[photoMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"moment" toKeyPath:#"moment" withMapping:momentMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:photoMapping method:RKRequestMethodAny pathPattern:nil keyPath:#"photos" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
*/
return photoMapping;
}
This is my json that my app received:
{
"user": {
"id": 38,
"email": "test#test.com",
"firstname": "bob",
"lastname": "tonny",
"gender": 0,
"created_at": "2014-04-19T11:00:55Z",
"updated_at": "2014-04-19T11:00:55Z",
"nickname": "bobby",
"facebook_id": null,
"birthday": "1990-02-14",
"city": "",
"country": "",
"facebook_token": null,
"facebook_token_expires_at": null,
"time_zone": "Europe/Paris",
"facebook_link_asked_at": null,
"sign_in_count": 0,
"confirmed": false,
"badge": {
"permanent": 0,
"contextual": 0
},
"avatar": null
}
}
You can see that there is no relation with device or devices here. But I have the exact following error:
error=Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No mappable object representations were found at the key paths searched." UserInfo=0xd0c1770 {DetailedErrors=(
), NSLocalizedFailureReason=The mapping operation was unable to find any nested object representations at the key paths searched: device, devices
The representation inputted to the mapper was found to contain nested object representations at the following key paths: user
This likely indicates that you have misconfigured the key paths for your mappings., NSLocalizedDescription=No mappable object representations were found at the key paths searched., keyPath=null}
I'm currently not able to find where the problem comes from.
The only relation between User and Device is set on the .xcdatamodelId like you can see on the following pictures:
relationship for User
relationship for Device
I took a lot at the descriptors: session.objectManager.responseDescriptors. There are several descriptors but none about any devices.
If anyone can just see where I'm missing something, I would really like to know it.
Thank you in advance.
I found the solution. It was not obvious at all. After adding my descriptor to the objectManager, I did that:
session.objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
That solved completely my problem. I don't know why it's important to precise here because I already set this property a long time ago on my code..
Edit: It WAS working ! I didn't touch anything but now it's not working.
Edit 2: I finally got it :
I was using
`[session.objectManager addResponseDescriptor:responseDescriptor];
session.objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[[RKObjectManager sharedManager] managedObjectRequestOperationWithRequest:request managedObjectContext:session.objectManager.managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)`
I changed [RKObjectManager sharedManager] by my variable session.objectManager and everything work fine !
I hope it will help someone else.
Please guide me about following problem.
I have two entities with relationship as shown following image
I am using latest version of RestKit with iOS 7
Now in my appDelegate i am using following mapping for "List" Entity
NSDictionary *listObjectMapping = #{
#"listID" : #"listID",
#"listName" : #"listName",
#"listSyncStatus" : #"listSyncStatus"
};
RKEntityMapping *listEntityMapping = [RKEntityMapping mappingForEntityForName:#"List" inManagedObjectStore:managedObjectStore];
[listEntityMapping addAttributeMappingsFromDictionary:listObjectMapping];
listEntityMapping.identificationAttributes = #[ #"listID" ];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:listEntityMapping
method:RKRequestMethodGET
pathPattern:#"/api/lists"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];
//Inverse mapping, to perform a POST
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[listEntityMapping inverseMapping]
objectClass:[List class]
rootKeyPath:nil
method:RKRequestMethodPOST];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"application/json"];
[objectManager addRequestDescriptor:requestDescriptor];
//Inverse mapping, to perform a PUT
requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[listEntityMapping inverseMapping]
objectClass:[List class]
rootKeyPath:nil
method:RKRequestMethodPUT];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"application/json"];
[objectManager addRequestDescriptor:requestDescriptor];
and using following mapping for my Task object
NSDictionary *taskObjectMapping = #{
#"listID" : #"listID",
#"taskID" : #"taskID",
#"taskName" : #"taskName",
#"taskCompletionStatus" : #"taskCompletionStatus",
#"taskSyncStatus" : #"taskSyncStatus"
};
RKEntityMapping *taskEntityMapping = [RKEntityMapping mappingForEntityForName:#"Task" inManagedObjectStore:managedObjectStore];
[taskEntityMapping addAttributeMappingsFromDictionary:taskObjectMapping];
taskEntityMapping.identificationAttributes = #[ #"taskID" ];
RKResponseDescriptor *taskResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:taskEntityMapping
method:RKRequestMethodGET
pathPattern:#"/api/list/:id"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:taskResponseDescriptor];
//Inverse mapping, to perform a POST
RKRequestDescriptor *taskRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[taskEntityMapping inverseMapping]
objectClass:[Task class]
rootKeyPath:nil
method:RKRequestMethodPOST];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"application/json"];
[objectManager addRequestDescriptor:taskRequestDescriptor];
//Inverse mapping, to perform a PUT
taskRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[taskEntityMapping inverseMapping]
objectClass:[Task class]
rootKeyPath:nil
method:RKRequestMethodPUT];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"application/json"];
[objectManager addRequestDescriptor:taskRequestDescriptor];
Now my question is how to add relationship mapping between these two entites ?
What would be proper way ?
If i use i use following line of code
[taskEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"list.listID"
toKeyPath:#"listID"
withMapping:listEntityMapping]];
a runtime error occurs saying "Unable to add mapping for keyPath listID, one already exists"
and if i use this
[listEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"listID"
toKeyPath:#"list.listID"
withMapping:taskEntityMapping]];
app crashes with this error the entity List is not key value coding-compliant for the key "list".'
and if i omit the above code and try to get listID from relationship
task.list.listID
it gives me "0". Can anyone tell me what exactly am i doing wrong or what should i do to accomplish above task. I can give more details on this if needed.
EDIT
but my request to all list returns following json
GET www.mydomain.com/api/lists
[
{"listID":"42","listName":"List 4","listSyncStatus":"1"},
{"listID":"41","listName":"List 3","listSyncStatus":"1"},
{"listID":"40","listName":"List 2","listSyncStatus":"1"}
]
and request to single list will return its task as follows
GET www.mydomain.com/api/list/42
[
{"taskID":"22","listID":"42","taskName":"Task 2","taskSyncStatus":"1","taskCompletionStatus":"1"},
{"taskID":"21","listID":"42","taskName":"Task 1","taskSyncStatus":"1","taskCompletionStatus":"1"}
]
i.e there is no cascading relationship in returned in json. is this wrong way or what am i missing here ?
Corrected After Accepting Answer
It turns out i was returning wrong json i.e. the returned json has no relationship in it while the iOS model has a relationship "tasks" so i edited my rest api to return correct nested json which is like below
[ { "listID" : "96",
"listName" : "List 1",
"listSyncStatus" : "1",
"tasks" : [ { "taskCompletionStatus" : "1",
"taskID" : "67",
"taskName" : "Task 2",
"taskSyncStatus" : "1"
},
{ "taskCompletionStatus" : "1",
"taskID" : "66",
"taskName" : "Task 1",
"taskSyncStatus" : "1"
}
]
},
{ "listID" : "97",
"listName" : "List 2",
"listSyncStatus" : "1",
"tasks" : [ { "taskCompletionStatus" : "1",
"taskID" : "69",
"taskName" : "Task 1",
"taskSyncStatus" : "1"
},
{ "taskCompletionStatus" : "1",
"taskID" : "68",
"taskName" : "Task 1",
"taskSyncStatus" : "1"
}
]
}
]
after returning above nested json, everything works like charm, specially this line
[listEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"tasks"
toKeyPath:#"tasks"
withMapping:taskEntityMapping]];
Hope this helps grasping relationship concepts for people like me out there.
You modal diagram shows that you have one-to-many relationship (One list has many tasks).
As far as i know, in this case you need to add relationship mapping on List entity only, no need on Task entity. Also for one-to-many relationship, you don't need to add list relationship under Task entity.
Your entities relationship should look like this
So try following
[listEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"YOUR_JSON_KEYPATH_HERE" toKeyPath:#"tasks" withMapping: taskEntityMapping]];
IMPORTANT
In above method
FromKeyPath parameter should be the name of your JSON key where the relationship starts.
toKeyPath parameter should be the relationship name that you have mentioned in Entity diagram. i.e; tasks.
withMapping should be the mapping of many entity. In you case taskEntityMapping
Hope this fix the issue.
Not sure why this is not working, but you can try to create the relationship mapping like this:
[taskEntityMapping addConnectionForRelationship:#"list" connectedBy:#{ #"listId": #"listId" }];
[listEntityMapping addConnectionForRelationship:#"tasks" connectedBy:#{ #"listId":#"listId"}];
I have two entities: Contact and Listing. A User can mark a specific Listing as its Favourite.
I set up the Relationships correctly and I'm able to add a Listing as a Favourite for the User.
The problem for me is the API side. It gives me only the ids of the relationship: contact_id and the listing_id.
How can I set up RestKit to map the relationships defined in the Favourites object I get from the server which only gives me the two object ids of a contact and a listing?
Restkit Version: 0.20.3
JSON for Favorite:
{
"contact_id": "1",
"created_at": "2013-11-06T15:02:21.056Z",
"id": "2",
"listing_id": "3",
"updated_at": "2013-11-06T15:02:21.056Z"
}
JSON for Contact:
{
"id": 1,
"favorites": [
{
"contact_id": "1",
"created_at": "2013-11-06T15:02:21.056Z",
"id": "2",
"listing_id": "3",
"updated_at": "2013-11-06T15:02:21.056Z"
}
],
"first_name": Max,
}
//////////
// Contact
//////////
RKEntityMapping *contactMapping = [RKEntityMapping mappingForEntityForName:#"PBContact" inManagedObjectStore:managedObjectStore];
contactMapping.identificationAttributes = #[ #"object_id" ];
[contactMapping addAttributeMappingsFromDictionary:#{ #"id": #"object_id" }];
[contactMapping addAttributeMappingsFromArray:#[ #"given_name", #"address", #"birthday",
#"city", #"company_name", #"country",
#"email", #"family_name", #"gender",
#"mobile_number", #"note", #"phone_number",
#"state", #"zip_code", #"created_at", #"updated_at" ]];
//////////
// Listing
//////////
RKEntityMapping *listingMapping = [RKEntityMapping mappingForEntityForName:#"PBListing" inManagedObjectStore:managedObjectStore];
listingMapping.identificationAttributes = #[ #"object_id" ];
[listingMapping addAttributeMappingsFromDictionary:#{ #"id": #"object_id", #"description": #"descriptions" }];
[listingMapping addAttributeMappingsFromArray:#[ #"address", #"name", #"bathrooms", #"bedrooms",
#"city", #"country", #"price", #"title",
#"zip_code", #"latitute", #"longitude", #"status",
#"total_area", #"year_built", #"property_type", #"listing_type",
#"size", #"lot_size", #"parking_spaces", #"view",
#"state", #"note", #"monthly_rent", #"created_at", #"updated_at" ]];
//////////
// Relationships
//////////
[contactMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"favorites" toKeyPath:#"favoriteListings" withMapping:listingMapping]];
[listingMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"favorites" toKeyPath:#"prospects" withMapping:contactMapping]];
Response Descriptor
RKResponseDescriptor *contactResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:contactMapping
method:RKRequestMethodAny
pathPattern:#"api/v1/contacts"
keyPath:nil
statusCodes:statusCodes];
You don't need (and should delete):
[listingMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"favorites" toKeyPath:#"prospects" withMapping:contactMapping]];
because the relationship is already being configured from the other side on the contactMapping. There shouldn't need to be any other changes by the look of it.
It isn't entirely clear why there are 3 ids:
"contact_id": "1",
"id": "2",
"listing_id": "3",
I'm assuming that contact_id always matches the outer contact that the favourites are nested in and isn't required. And that id is the useful piece of information (so your mapping is correct).
In your Core Data model, favoriteListings and prospects should be the inverse of each other.
Based on your latest comments, I think you need to create a new and different listing mapping. This mapping only contains #"listing_id" : #"object_id". This will either link to an existing listing entity or create a placeholder that can be filled in later. This is the mapping that you should use as the relationship on contactMapping.
this is what my sample code looks like:
{
"name": "Ahmad Mansour",
"subjects": [
{
"parent_subject_name": "Arabic",
"subject_name": "Shafahi",
"exams": [
{
"score": "30.00",
"exam_name": "Sa3i 1 "
},
{
"score": "50.00",
"exam_name": "sa3i 2"
},
{
"score": "100.00",
"exam_name": "First Semester Exam"
}
]
},
{
"parent_subject_name": "Arabic",
"subject_name": "Khati",
"exams": [
{
"score": "50.00",
"exam_name": "Sa3i 1 "
},
{
"score": "60.00",
"exam_name": "sa3i 2"
},
{
"score": "95.00",
"exam_name": "First Semester Exam"
}
]
},
for the subject entity.. my mapping works just fine:
RKEntityMapping *subjectEntityMapping = [RKEntityMapping mappingForEntityForName:kSubjectIdentity inManagedObjectStore:model.managedObjectStore];
[subjectEntityMapping addAttributeMappingsFromDictionary:#{ #"subject_name": #"name",
#"parent_subject_name" :#"parent_name"
}];
subjectEntityMapping.identificationAttributes = #[ #"name" ];
RKResponseDescriptor *studentResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:subjectEntityMapping pathPattern:kGradesPath keyPath:#"subjects" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[model.objectManager addResponseDescriptor:studentResponseDescriptor];
but when i do the exam score mapping.. things blow up:
RKEntityMapping *examEntityMapping = [RKEntityMapping mappingForEntityForName:kExamIdentity inManagedObjectStore:model.managedObjectStore];
[examEntityMapping addAttributeMappingsFromDictionary:#{ #"exams.exam_name": #"name" }];
examEntityMapping.identificationAttributes = #[ #"name" ];
RKResponseDescriptor *examResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:examEntityMapping pathPattern:kGradesPath keyPath:#"subjects" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[model.objectManager addResponseDescriptor:examResponseDescriptor];
i get the following error:
E restkit.object_mapping:RKMappingOperation.m:431 Failed transformation of value at keyPath 'exams.exam_name' to representation of type 'NSString': Error Domain=org.restkit.RKValueTransformers.ErrorDomain Code=3002 "Failed transformation of value '(
"Sa3i 1 ",
"sa3i 2",
"First Semester Exam"
)' to NSString: none of the 2 value transformers consulted were successful." UserInfo=0x9a508a0 {detailedErrors=(
"Error Domain=org.restkit.RKValueTransformers.ErrorDomain Code=3002 \"The given value is not already an instance of 'NSString'\" UserInfo=0x9a50800 {NSLocalizedDescription=The given value is not already an instance of 'NSString'}",
"Error Domain=org.restkit.RKValueTransformers.ErrorDomain Code=3000 \"Expected an `inputValue` of type `NSNull`, but got a `__NSArrayI`.\" UserInfo=0x9a50830 {NSLocalizedDescription=Expected an `inputValue` of type `NSNull`, but got a `__NSArrayI`.}"
I also tried this mapping, but i get the exact same error:
[examEntityMapping addAttributeMappingsFromDictionary:#{ #"exam_name": #"name" }];
examEntityMapping.identificationAttributes = #[ #"name" ];
RKResponseDescriptor *examResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:examEntityMapping pathPattern:kGradesPath keyPath:#"subjects.exams" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
ideas?
You shouldn't have a response descriptor for exams. It's nested data in your subject so it should be mapped using a relationship on the subject mapping.
Using the response descriptor doesn't work because you're trying to map into 2 arrays when the mapping only caters for one. Hence you get an error when RestKit tries to convert an array into a string.
Also, for your exam mapping you should probably specify multiple attributes for the unique identity as exam names are used repeatedly for different instances...
I'm new to CoreData and Restkit, and I'm having a lot of trouble with the following error.
I'm using restkit to parse some venues returned from Foursquare. Unfortunately I keep getting this error:
2013-07-12 16:12:46.369 FlokMobile[5903:c07] CoreData: error: Serious application error. Exception was caught during Core Data change processing. This is usually a bug within an observer of NSManagedObjectContextObjectsDidChangeNotification. [<FoursquareVenue 0x1ec5fb00> valueForUndefinedKey:]: the entity Venue is not key value coding-compliant for the key "distance". with userInfo {
NSTargetObjectUserInfoKey = "<FoursquareVenue: 0x1ec5fb00> (entity: Venue; id: 0xb472c10 <x-coredata://EAB387D9-C6CB-4873-84C5-1C32E137FFE9/Venue/p49> ; data: {\n canonicalUrl = \"https://foursquare.com/v/sams-cable-car-lounge/5171ef7b498e4035a7f7a371\";\n location = \"0xb477860 <x-coredata://EAB387D9-C6CB-4873-84C5-1C32E137FFE9/Location/p30>\";\n name = \"Sam's Cable Car Lounge\";\n venueID = 5171ef7b498e4035a7f7a371;\n})";
NSUnknownUserInfoKey = distance;
}
2013-07-12 16:12:46.370 FlokMobile[5903:c07] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<FoursquareVenue 0x1ec5fb00> valueForUndefinedKey:]: the entity Venue is not key value coding-compliant for the key "distance".'
*** First throw call stack:
(0x1e42012 0x1c67e7e 0x1ecafb1 0x24d1d4 0x168000b 0x1e8fc4 0x169e247 0x1738c62 0x2af8a5 0x2aa735 0x2ad011 0x17284f9 0x1e9c0c5 0x1df6efa 0x165cbb2 0x1bf163 0x258d2f 0x1ba596 0x1b9869 0x1e6558 0x25b025 0x1e0cc1 0x2697731 0x26a6014 0x26967d5 0x1de8af5 0x1de7f44 0x1de7e1b 0x28dd7e3 0x28dd668 0xbabffc 0x2e7d 0x2da5)
libc++abi.dylib: terminate called throwing an exception
Here is the code that I used to setup my key mappings:
// Setup Restkit for Foursquare
//Setup mapping for response
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"FoursquareModel" ofType:#"momd"]];
//mutableCopy might not be necessary
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
//Initialize Core Data stack
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *persistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(persistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
//Set default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
//Configure Object Manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"https://api.foursquare.com/v2/"]];
objectManager.managedObjectStore = managedObjectStore;
[RKObjectManager setSharedManager:objectManager];
RKEntityMapping *venueMapping = [RKEntityMapping mappingForEntityForName:#"Venue" inManagedObjectStore:managedObjectStore];
RKEntityMapping *locationMapping = [RKEntityMapping mappingForEntityForName:#"Location" inManagedObjectStore:managedObjectStore];
[venueMapping addAttributeMappingsFromDictionary:#{
#"name": #"name",
#"id": #"venueID",
#"canonicalUrl": #"canonicalUrl"}];
venueMapping.identificationAttributes = #[#"venueID"];
[locationMapping addAttributeMappingsFromArray:#[ #"address",#"cc",#"city",#"country",#"crossStreet",#"distance",#"lat",#"lng",
#"postalCode",#"state"]];
//[venueMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"location" toKeyPath:#"location" withMapping:locationMapping]];
[venueMapping addRelationshipMappingWithSourceKeyPath:#"response.venues.location" mapping:locationMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor
responseDescriptorWithMapping:venueMapping
pathPattern:nil
keyPath:#"response.venues"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];
And my CoreData models:
Everytime I run the app, it always fails on encoding the same key. It is able to load the venues and map the keys to the Venue entity. I believe there might be a problem with the way I'm handling the relationship between the Venue and Location entity.
Here's what the JSON that I'm getting looks like:
{
"meta" : {
"code" : 200
},
"response" : {
"venues" : [
{
"id" : "40bbc700f964a520b1001fe3",
"categories" : [
{
"pluralName" : "Plazas",
"primary" : true,
"shortName" : "Plaza",
"id" : "4bf58dd8d48988d164941735",
"name" : "Plaza",
"icon" : {
"prefix" : "https://foursquare.com/img/categories_v2/parks_outdoors/plaza_",
"suffix" : ".png"
}
}
],
"stats" : {
"checkinsCount" : 75856,
"usersCount" : 40342,
"tipCount" : 176
},
"venuePage" : {
"id" : "34303229"
},
"storeId" : "",
"contact" : {
"phone" : "4157817880",
"formattedPhone" : "(415) 781-7880",
"twitter" : "unionsquaresf"
},
"hereNow" : {
"groups" : [],
"count" : 0
},
"verified" : true,
"url" : "http://visitunionsquaresf.com",
"referralId" : "v-1373553758",
"restricted" : true,
"location" : {
"address" : "Union Square Park",
"city" : "San Francisco",
"distance" : 68,
"postalCode" : "94108",
"crossStreet" : "btwn Post, Stockton, Geary & Powell St.",
"country" : "United States",
"lat" : 37.787750172585,
"lng" : -122.40762822536455,
"state" : "CA",
"cc" : "US"
},
"canonicalUrl" : "https://foursquare.com/v/union-square/40bbc700f964a520b1001fe3",
"specials" : {
"count" : 0,
"items" : []
},
So here's what I've figured out: Restkit, for some bizarre reason is looking for the key "distance" in the entity "venue"
"distance" is not an attribute in the JSON received from Foursquare, nor is it explicitly mapped anywhere by code.
I fixed the immediate issue temporarily by adding the "distance" key to the "venue" entity. I don't know why it works, and it might have some weird implications later on.
If anyone can shed more light on this issue, I would gladly appreciate it.
Hopefully I'm doing something wrong in my code and I just don't see it!
EDIT: Even with Blake's suggestion, I was getting the same error.
I think you have your response descriptor and relationship mapping key paths all twisted up. You are double specifying the response.venues key path in the descriptor and then again in a self-referential relationship mapping. Try this instead:
RKEntityMapping *venueMapping = [RKEntityMapping mappingForEntityForName:#"Venue" inManagedObjectStore:managedObjectStore];
RKEntityMapping *locationMapping = [RKEntityMapping mappingForEntityForName:#"Location" inManagedObjectStore:managedObjectStore];
[venueMapping addAttributeMappingsFromDictionary:#{
#"name": #"name",
#"id": #"venueID",
#"canonicalUrl": #"canonicalUrl"}];
venueMapping.identificationAttributes = #[#"venueID"];
[locationMapping addAttributeMappingsFromArray:#[ #"address",#"cc",#"city",#"country",#"crossStreet",#"distance",#"lat",#"lng",
#"postalCode",#"state"]];
[venueMapping addRelationshipMappingWithSourceKeyPath:#"location" mapping:locationMapping];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor
responseDescriptorWithMapping:venueMapping
pathPattern:nil
keyPath:#"response.venues"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];
Using the logging or unit tests can make debugging your mappings much easier.