RestKit: how to map URL param to object attribute - objective-c

I've got REST service method like this one
/GetOfficeDocument?officeId=259
which returns an array of documents. Document in the app is a NSManagedObject object that has relationship to an office. How can I map officeId param to office relationship of my Document?
I know I should override objectLoader:willMapData:, but I don't know what exactly should I do inside of this method. The documentation is useless.
UPD. The response of the server looks like this:
[{"AddedDate":"\/Date(1261484400000+0400)\/","Title":"Some text","Uri":"\/Document\/News\/851"}]
As you see, officeId is not contained in response, only in URL. I can extract it in objectLoader:willMapData: using
[[[loader URL] queryParameters] objectForKey:#"officeId"]
but where should I put it next? Mappable data parameter is a mutable array, what should I place there? No idea.

You could try to inject the OfficeId value in each document item returned in the response like so:
- (void)objectLoader:(RKObjectLoader *)loader willMapData:(inout __autoreleasing id *)mappableData
{
NSString *officeId = [[[loader URL] queryParameters] objectForKey:#"officeId"];
NSMutableArray *newMappableData = [[NSMutableArray alloc] initWithCapacity:[*mappableData count]];
for (NSDictionary *documentDict in *mappableData)
{
NSMutableDictionary = newDocumentDict = [documentDict mutableCopy];
[newDocumentDict setObject:officeId forKey:#"OfficeId"];
[newMappableData addObject:newDocumentDict];
}
*mappableData = newMappableData;
}
And use something similar to the following in your Document mapping:
[documentMapping mapAttributes:#"AddedDate", #"Title", #"Uri", #"OfficeId", nil];
[documentMapping mapKeyPath:#"" toRelationship:#"office" withMapping:officeMapping];
[documentMapping connectRelationship:#"office" withObjectForPrimaryKeyAttribute:#"OfficeId"];

I usually add the RKObjectMapping to the managedObject class
Add this to your Document.h
+ (RKObjectMapping *)objectMapping;
Add this method to your Document.m
+ (RKObjectMapping *)objectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForClass:[self class] inManagedObjectStore:[[RKObjectManager sharedManager] objectStore]];
mapping.primaryKeyAttribute = #"word";
[mapping mapKeyPath:#"word" toAttribute:#"word"];
[mapping mapKeyPath:#"min_lesson" toAttribute:#"minLesson"];
}
Off course you should change the key paths to your Document object properties. each pair is the name of the key on the server responds and it's corresponded keyPath on your managedObject.
Then when you initialize the objectManager you can set the mapping for each managedObject you have.
RKManagedObjectStore *store = [RKManagedObjectStore objectStoreWithStoreFilename:databaseName usingSeedDatabaseName:seedDatabaseName managedObjectModel:nil delegate:self];
objectManager.objectStore = store;
//set the mapping object from your Document class
[objectManager.mappingProvider setMapping:[SRLetter objectMapping] forKeyPath:#"Document"];
YOu can find a great tutorial here - RestKit tutorial. In the middle of the article you will find data about mapping.

Related

iOS7 is there a lightweight JSON to Object mapper, (NOT RestKit or NSJSONSerialization)?

My current project uses AFNetworking 2.2 and in general refuses to compile when I add Restkit. Is there a way for me to get some equivalent of RKObjectMapping as defined below from some other lightweight library? I'm talking about taking JSON and turning it into a custom value object, not just a dictionary or array.
Google GSON for Android comes to mind, is there something like that for iOS?
What' I'm trying to accomplish:
static RKObjectMapping* mapping = nil;
+(RKObjectMapping*)objectMapping
{
if(mapping != nil)
{
return mapping;
}
//allows automatic unpacking of JSON payloads into Value Objects
//https://github.com/RestKit/RestKit/wiki/Object-Mapping
//JSON - VO
mapping = [RKObjectMapping mappingForClass:[MyVO class]];
[mapping addAttributeMappingsFromDictionary:#{
#"label": #"label",
#"icon": #"iconName",
#"action": #"actionName",
#"children": #"children"
}];
return mapping;
}
Have you tried NSJsonSerialization (https://developer.apple.com/library/ios/documentation/foundation/reference/nsjsonserialization_class/Reference/Reference.html)? It seems to accomplish what you need. I use it whenever I need to parse anything in JSON format,
-(id) initWithDictionary:(NSDictionary*) dict {
id self = [super init];
if (id) {
self.label = dict[#"label"];
self.icon = dict[#"iconName"];
self.action = dict[#"actionName"];
self.children = dict[#"children"];
}
return id;
}

iOS, Remote server search with RestKit

I'm working on an app where I want to make a remote search to a server. I want RestKit to save the retrieved data to the database. I first perform a local search (which currently works) then I want to make the remote search and then update a table view with the new results.
I'm having two problems, 1. how should my mapping look like and 2. the json returns an array with two different kinds of objects.
The URL looks like this:
search.json?search=[search string]
The JSON it returns looks like this:
[
{
"event": {
"id": 2,
[...]
},
{
"news": {
"id": 16,
[...]
}
Where event and news is two kind of objects.
In my app I have three models, Post (abstract entity and superclass) NewsPost (subclass to Post) and Event (subclass to Post).
My mappings looks like this:
RKManagedObjectMapping* newsMapping = [RKManagedObjectMapping mappingForClass:[NewsPost class] inManagedObjectStore:objectManager.objectStore];
newsMapping.primaryKeyAttribute = #"newsId";
newsMapping.rootKeyPath = #"news";
[newsMapping mapKeyPath:#"id" toAttribute:#"newsId"];
RKManagedObjectMapping *eventMapping = [RKManagedObjectMapping mappingForClass:[CalendarEvent class] inManagedObjectStore:objectManager.objectStore];
eventMapping.primaryKeyAttribute = #"calendarId";
eventMapping.rootKeyPath = #"calendars";
[eventMapping mapKeyPath:#"id" toAttribute:#"calendarId"];
// These two works.
[objectManager.mappingProvider setObjectMapping:newsMapping forResourcePathPattern:#"/package_components/1/news"];
[objectManager.mappingProvider setObjectMapping:eventMapping forResourcePathPattern:#"/package_components/1/calendars"];
// I don't know how these should look/work.
// Since the search word can change
[objectManager.mappingProvider setObjectMapping:eventMapping forResourcePathPattern:#"/package_components/1/search\\.json?search="];
[objectManager.mappingProvider setObjectMapping:newsMapping forResourcePathPattern:#"/package_components/1/search\\.json?search="];
My search code looks like this (local search works):
- (void)setUpSearch
{
if (self.searchField.text != nil) {
[self.posts removeAllObjects];
[self.events removeAllObjects];
[self.news removeAllObjects];
// Search predicates.
// Performs local search.
NSPredicate *contactNamePredicate = [NSPredicate predicateWithFormat:#"contactName contains[cd] %#", self.searchField.text];
NSPredicate *contactDepartmentPredicate = [NSPredicate predicateWithFormat:#"contactDepartment contains[cd] %#", self.searchField.text];
[...]
NSArray *predicatesArray = [NSArray arrayWithObjects:contactNamePredicate, contactDepartmentPredicate, contactEmailPredicate, contactPhonePredicate, linkPredicate, titlePredicate, nil];
NSPredicate *predicate = [NSCompoundPredicate orPredicateWithSubpredicates:predicatesArray];
self.posts = [[Post findAllWithPredicate:predicate] mutableCopy];
if (self.posts.count != 0) {
self.noResultsLabel.hidden = YES;
for (int i = 0; i < self.posts.count; i++) {
Post * post = [self.posts objectAtIndex:i];
if (post.calendarEvent == YES) {
[self.events addObject:post];
} else {
[self.news addObject:post];
}
}
}
// reload the table view
[self.tableView reloadData];
[self performRemoteSearch];
}
}
- (void)search
{
[self setUpSearch];
[self hideKeyboard];
[self performRemoteSearch];
}
- (void)performRemoteSearch
{
// Should load the objects from JSON
// Note that the searchPath can vary depending on search text.
NSString *searchPath = [NSString stringWithFormat:#"/package_components/1/search.json?search=%#", self.searchField.text];
RKObjectManager *objectManager = [RKObjectManager sharedManager];
[objectManager loadObjectsAtResourcePath:searchPath delegate:self];
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects
{
// This never gets called.
// Should update my arrays and then update the tableview, but it never gets called.
// Instead I get Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "Could not find an object mapping for keyPath: ''
}
Any tips on how i should or could do would be greatly appreciated.
I haven't used Managed Objects before but the first thing to do here is to activate the restkit log over object mapping and network request so you can check what is restkit getting from the server and how the mapping is working.
//This can be added in your app delegate
RKLogConfigureByName("RestKit/Network", RKLogLevelDebug);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
In second place, according to your JSON and that your search path changes, I think is better to use mapping for key path instead of resource path pattern. So you should try to map by key, like in this example:
RKObjectMapping* articleMapping = [RKObjectMapping mappingForClass:[Article class]];
[articleMapping mapKeyPath:#"title" toAttribute:#"title"];
[articleMapping mapKeyPath:#"body" toAttribute:#"body"];
[articleMapping mapKeyPath:#"author" toAttribute:#"author"];
[articleMapping mapKeyPath:#"publication_date" toAttribute:#"publicationDate"];
[[RKObjectManager sharedManager].mappingProvider setMapping:articleMapping forKeyPath:#"articles"];
And then load your data like:
- (void)loadArticles {
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/articles" delegate:self];
}
The other way to do this is to map by object, so RestKit detects the kind of object and performs the mapping and you make the request to any path.
If you have any question please leave a comment and I can improve my answer as needed.
I've never tried answering a question with a bounty before, let me try to give a useful answer from some recent work =)
1. how should my mapping look like
From your code, everything looks pretty fine. Are there any nesting of objects? Do you need to serialize for posting back to the server?
2. the json returns an array with two different kinds of objects.
Are your attributes the same (i.e. Event has a title, event has a date) with no surprises? If not, you have to use dynamic nesting.
If a resource path (i.e. your search path) receives a collection with different objects (your case), you have to use dynamic object mapping to load the objects.
Since you can edit the JSON structure, things can be simpler by leveraging on RestKit.
- Make sure the JSON has a root_key_path for the two different type of objects.
From an old experiment and some googling, RestKit can properly map a json output with different objects if they have proper rootKeyPaths. Resulting JSON should have a rough structure like:
{
"news" : [
{
"id" : 1,
"title" : "Mohawk guy quits"
},
{
"id" : 2,
"title" : "Obama gets mohawk"
}
],
"events" : [
{
"id" : 1,
"name" : "testing"
},
{
"id" : 2,
"name" : "testing again"
}
]
}
I cannot be sure 100% the above is correct. You can experiment by making your API return news only, if it works, then adding the events data into the mix.
- Load the objects from server
// Make a NS dictionary and use stringByAppendingQueryParameters
NSDictionary *searchParams = [NSDictionary dictionaryWithKeysAndObjects:
#"query",#"myQuery",
#"location",#"1.394168,103.895473",
nil];
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:[#"/path/to/resource.json" stringByAppendingQueryParameters:searchParams] delegate:objectLoaderDelegate];
- Handle the "real" searching in your objectLoader Delegate
If it worked, the objects should be mapped to your Coredata entities. You can perform a local search using the NSPredicate method you posted above.
I prefer the design pattern where RestKit uses loadObjects... to get data from the server and maps it, the rest of the processing is done locally. This decoupling makes things more "app-like". You can do other form of manipulation using NSPredicates.
- (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray*)objects {
// Do some processing here on the array of returned objects or cede control to a method that
// you've built for the search, like the above method.
}
One example, if the search use case is restaurants nearby, it will probably make sense to load all the restaurants within the current lat/lon, and then perform the local filtering by name using Coredata. Your server will heart you.
Let me know and I'll try to improve the answer further.

Restkit Object Mapping Two Classes Bad Access

I am mapping two classes of objects with RestKit. When I do either of them by themselves, it works out perfectly fine. But when I call them together, it will crash on line 449 in RKObjectMappingOperation.m,
[destinationSet setSet:destinationObject];
With an "EXC_BAD_ACCESS" error.
Here are my two mapping methods:
- (RKObjectLoader *)saves
{
// Create an object manager and connect core data's persistent store to it
RKObjectManager *objectManager = [RKObjectManager sharedManager];
RKManagedObjectStore* objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:#"Db.sqlite"];
objectManager.objectStore = objectStore;
// Define our author mapping for saved places
RKManagedObjectMapping *authorMapping = [RKManagedObjectMapping mappingForEntityWithName:#"Person"];
[authorMapping mapAttributes:#"uid", nil];
// Define our place mapping
RKManagedObjectMapping *placeMapping = [RKManagedObjectMapping mappingForEntityWithName:#"Place"];
[placeMapping mapAttributes:#"uid",#"name",#"address", nil];
// Now, connect the two via a save
RKManagedObjectMapping *saveMapping = [RKManagedObjectMapping mappingForEntityWithName:#"Save"];
[saveMapping mapAttributes:#"uid", #"timestamp", nil];
[saveMapping mapKeyPath:#"place" toRelationship:#"place" withMapping:placeMapping];
[saveMapping mapKeyPath:#"author" toRelationship:#"author" withMapping:authorMapping];
// We expect to find the place entity inside of a dictionary keyed "saves"
[objectManager.mappingProvider setMapping:saveMapping forKeyPath:#"saves"];
// Prepare our object loader to load and map objects from remote server, and send
RKObjectLoader *objectLoader = [objectManager objectLoaderWithResourcePath:#"places/saves" delegate:self];
objectLoader.method = RKRequestMethodGET;
[objectLoader send];
return objectLoader;
}
- (RKObjectLoader *)recommends
{
// Create an object manager and connect core data's persistent store to it
RKObjectManager *objectManager = [RKObjectManager sharedManager];
RKManagedObjectStore* objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:#"Db.sqlite"];
objectManager.objectStore = objectStore;
// Define our author mapping for recommended places
RKManagedObjectMapping *authorMapping = [RKManagedObjectMapping mappingForEntityWithName:#"Person"];
[authorMapping mapAttributes:#"uid", nil];
// Define our place mapping
RKManagedObjectMapping *placeMapping = [RKManagedObjectMapping mappingForEntityWithName:#"Place"];
[placeMapping mapAttributes:#"uid",#"name",#"address", nil];
// Now, connect the two via a recommend
RKManagedObjectMapping *recommendMapping = [RKManagedObjectMapping mappingForEntityWithName:#"Recommend"];
[recommendMapping mapAttributes:#"uid", #"timestamp", nil];
[recommendMapping mapKeyPath:#"place" toRelationship:#"place" withMapping:placeMapping];
[recommendMapping mapKeyPath:#"author" toRelationship:#"author" withMapping:authorMapping];
// We expect to find the place entity inside of a dictionary keyed "recommends"
[objectManager.mappingProvider setMapping:recommendMapping forKeyPath:#"recommends"];
// Prepare our object loader to load and map objects from remote server, and send
RKObjectLoader *objectLoader = [objectManager objectLoaderWithResourcePath:#"places/recommends" delegate:self];
objectLoader.method = RKRequestMethodGET;
[objectLoader send];
return objectLoader;
}
When I call one, or the other, it works. When I call both,
[self saves];
[self recommends];
It crashes. Any idea why?
The call to set objectManager.objectStore is causing the previously set objectStore to be released from objectManager. The first call, [self saves] creates and sets an objectStore object, then second call [self recommends] repeats this, thereby removing the first one set in [self saves]. Some time during the processing started off by [self saves], the original (released) objectStore object is being accessed, hence the crash.
A potential fix would be to refactor out the objectStore setter into a separate method which is called by both methods, or wrap it in an if (!objectManager.objectStore) { ... } statement.

Mapping a JSON response to an object using RestKit and Objective-C

I am relatively new to Objective-C and am attempting to use RestKit to receive a JSON response from a web service. I have successfully received the data back to my application, which looks like this viewing the response:
{id:"1","Translation":"Test"}
I would like to map this translation to my "Translation" object in my application, but have tried a few different ways but am not sure how to achieve this.
So my questions are:
How can I map this response to my Translation object
Am I doing this correctly, creating a method to complete this call outwit my view controller?
My Translation Object
#implementation Translation
#synthesize identifier = _identifier;
#synthesize translation = _translation;
- (NSDictionary*)elementToPropertyMappings {
return [NSDictionary dictionaryWithKeysAndObjects:
#"id", #"identifier",
#"translation", #"translation",
nil];
}
#end
My Translate Method
- (NSString *)performTranslation:(NSString *)translation
{
NSString *data = [[NSString alloc] initWithFormat:#"{\"SourceId\": \"%#\",\"RegionTag\": \"%#\",\"InputString\": \"%#\"}", #"1", #"Glasgow", translation];
NSString *post = data;
RKRequest *MyRequest = [[RKRequest alloc] initWithURL:[[NSURL alloc] initWithString:#"http://my.url.com/Translation/Translate"]];
MyRequest.method = RKRequestMethodPOST;
MyRequest.HTTPBodyString = post;
MyRequest.additionalHTTPHeaders = [[NSDictionary alloc] initWithObjectsAndKeys:#"application/json", #"Content-Type", #"application/json", #"Accept", nil];
[MyRequest send];
RKResponse *Response = [MyRequest sendSynchronously];
return Response.bodyAsString; <--- looking to map this to translation object here
}
The snippet of your code seems a bit outdated. I strongly recommend reading the newest Object Mapping guide in order to leverage RestKit into it's fullest potential - especially the part Mapping without KVC.
Edit:
In order to post an object with RestKit and receive back an answer, we define a TranslationRequest class that will hold our request & Translation to hold our response.
Firstly, we set up our RKObjectManager and mappings (i usually do this in my AppDelegate):
RKObjectManager *manager = [RKObjectManager objectManagerWithBaseURL:kOurBaseUrl];
[manager setSerializationMIMEType:RKMIMETypeJSON];
//this is a singleton, but we keep the manager variable to avoid using [RKObjectManager sharedManager] all the time
//Here we define a mapping for the request. Note: We define it as a mapping from JSON to entity and use inverseMapping selector later.
RKObjectMapping *translationRequestMapping = [RKObjectMapping mappingForClass:[TranslationRequest class]];
[translationRequestMapping mapKeyPath:#"RegionTag" toAttribute:#"regionTag"];
...
[[manager mappingProvider] setSerializationMapping:[translationRequestMapping inverseMapping] forClass:[TranslationRequest class]];
//now we define the mapping for our response object
RKObjectMapping *translationMapping = [RKObjectMapping mappingForClass:[Translation class]];
[translationMapping mapKeyPath:#"id" toAttribute:#"identifier"];
[translationMapping mapKeyPath:#"Translation" toAttribute:#"translation"];
[[manager mappingProvider] addObjectMapping:mapping];
//finally, we route our TranslationRequest class to a given endpoint
[[manager router] routeClass:[TranslationRequest class] toResourcePath:kMyPostEndpoint];
This should be enough of the necessary setup. We can call our backend anywhere in the code (e.g. in any controller) like this:
//we create new TranslationRequest
TranslationRequest *request = [[TranslationRequest alloc] init];
[request setRegionTag:#"Hello"];
....
//then we fetch the desired mapping to map our response with
RKObjectMapping *responseMapping = [[RKObjectManager sharedManager].mappingProvider objectMappingForClass:class]
//and just call it. Be sure to let 'self' implement the required RKObjectManagerDelegate protocol
[[RKObjectManager sharedManager] postObject:request mapResponseWith:responseMapping delegate:self];]
Try this approach and let me know if you need any assistance.. I was not able to test it fully as i don't have any suitable backend that will return the responses, but judging from the RestKit log this should work.
You need to pass the returned JSON string into a JSON parser. I use SBJSON. You can then use the resulting dictionary to populate the properties of your object.
RestKit seems to have native objects that encapsulate four different JSON parsers. However, I'd advise caution because they seem to assume that the top level parsed object will always be a dictionary.
As another aside, the example in your question is not valid JSON. It should look like this:
{"id":"1","Translation":"Test"}

RestKit: How does one post an array of objects?

Question summary:
Consider a class SyncObject that is KVC-compliant with properties such as: time, someValue, lastChange, uuid.
Consider an NSArray containing exclusively instances of SyncObject.
I need to submit the array to the server as a JSON array.
How would one submit this array to the server using HTTP POST using RestKit?
Example array:
[
{
"time": "14:45 10/21/2011",
"someValue": "15",
"lastChange": "14:45 10/21/2011",
"uuid": "0b07c510-f4c8-11e0-be50-0800200c9a66"
},
{
"time": "14:50 10/21/2011",
"someValue": "62",
"lastChange": "14:51 10/21/2011",
"uuid": "1a6d4480-f4c8-11e0-be50-0800200c9a66"
}
]
Details
I have an array of objects that I need to the server as JSON. It seems to me that RestKit is the easiest way to do this: I'm trying to avoid converting objects into a set of NSDictionary objects, and then using some JSON encoder to get JSON which I can POST to the server.
So, having created the array, and having set up the mapping for the class of objects stored in the array, I naturally try to POST to the server.
RKObjectManager* mgr = [RKObjectManager objectManagerWithBaseURL:#"http://localhost/someweb/api/"];
mgr.serializationMIMEType = RKMIMETypeFormURLEncoded;
mgr.client.username = #"username";
mgr.client.password = #"password";
RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
[mapping mapKeyPath: #"time" toAttribute:#"time" ];
[mapping mapKeyPath: #"someValue" toAttribute:#"someValue" ];
[mapping mapKeyPath: #"lastChange" toAttribute:#"lastChange" ];
[mapping mapKeyPath: #"uuid" toAttribute:#"uuid" ];
RKObjectMapping* mappingForSerialization = [mapping inverseMapping];
[mgr.mappingProvider setSerializationMapping:mappingForSerialization
forClass:[NSManagedObject class]];
[mgr.router routeClass:[NSManagedObject class] toResourcePath:#"/sync" forMethod:RKRequestMethodPOST];
[mgr postObject:array delegate:nil/*self*/];
However, this is what I get out:
2011-10-11 14:57:51.769 AppConnect[1974:6e0b] *** Terminating app due to uncaught exception '(null)', reason: 'Unable to find a routable path for object of type '__NSArrayI' for HTTP Method 'POST''
Apparently, RestKit does not know how to handle NSArrays.
How does one post an array of objects using RestKit?
I've tried something different: I replaced the last line with a manual send through RKObjectLoader.
//[mgr postObject:[NSMutableDictionary dictionaryWithObject:array forKey:#"data"] delegate:nil/*self*/];
NSString* syncPath = #"/sync";
RKObjectLoader * objectLoader = [mgr objectLoaderWithResourcePath:syncPath delegate:self];
objectLoader.serializationMIMEType = RKMIMETypeJSON;
objectLoader.method = RKRequestMethodPOST;
//objectLoader.objectClass = [NSManagedObject class];
//objectLoader.managedObjectStore = mgr.objectStore;
objectLoader.params = [NSDictionary dictionaryWithObject:array
forKey:#"MyData"];
[objectLoader send];
Unfortunately, this does not apply mapping of any sort, and instead transmits an array of objects' descriptions. Setting serializationMIMEType also does not affect the structure of transmitted contents, and params are always transmitted as application/x-www-form-urlencoded.
I also tried assigning serialization mapping and passing the object as targetObject and sourceObject (this seems to be what RestKit does internally in -[RKObjectManager postObject:delegate:]).
RKObjectLoader * objectLoader = [mgr objectLoaderWithResourcePath:syncPath delegate:self];
objectLoader.method = RKRequestMethodPOST;
//objectLoader.objectClass = [NSManagedObject class];
//objectLoader.managedObjectStore = mgr.objectStore;
objectLoader.params = [NSMutableDictionary dictionaryWithObject:array
forKey:#"MyData"];
objectLoader.serializationMapping = mapping;
objectLoader.serializationMIMEType = RKMIMETypeJSON;
objectLoader.sourceObject = objectLoader.params;
objectLoader.targetObject = objectLoader.params;
[objectLoader send];
Unfortunately, no mapping occurs this way:
2011-10-12 12:36:48.143 MyProject[5119:207] D restkit.network:RKObjectLoader.m:290 POST or PUT request for source object {
MyData = (
"<NSManagedObject: 0x5935430> (entity: SomeRecord; id: 0x5934da0 <x-coredata://64DF9977-DA50-4FCD-8C20-4132E58439BF/SomeRecord/p1> ; data: <fault>)",
"<NSManagedObject: 0x5935730> (entity: SomeRecord; id: 0x5934db0 <x-coredata://64DF9977-DA50-4FCD-8C20-4132E58439BF/SomeRecord/p2> ; data: <fault>)"
);
}, serializing to MIME Type application/json for transport...
2011-10-12 12:36:48.143 MyProject[5119:207] D restkit.object_mapping:RKObjectMappingOperation.m:428 Starting mapping operation...
2011-10-12 12:36:48.145 MyProject[5119:207] T restkit.object_mapping:RKObjectMappingOperation.m:291 Did not find mappable attribute value keyPath 'time'
2011-10-12 12:36:48.145 MyProject[5119:207] T restkit.object_mapping:RKObjectMappingOperation.m:291 Did not find mappable attribute value keyPath 'someValue'
2011-10-12 12:36:48.145 MyProject[5119:207] T restkit.object_mapping:RKObjectMappingOperation.m:291 Did not find mappable attribute value keyPath 'lastChange'
2011-10-12 12:36:48.145 MyProject[5119:207] T restkit.object_mapping:RKObjectMappingOperation.m:291 Did not find mappable attribute value keyPath 'uuid'
2011-10-12 12:36:48.145 MyProject[5119:207] D restkit.object_mapping:RKObjectMappingOperation.m:448 Mapping operation did not find any mappable content
2011-10-12 12:36:48.146 MyProject[5119:207] T restkit.network:RKRequest.m:211 Prepared POST URLRequest '<NSMutableURLRequest http://someurl/api/sync?request=provide_key>'. HTTP Headers: {
Accept = "application/json";
"Content-Length" = 0;
}. HTTP Body: .
The restkit does not fund routable path for NSArray, because you defined your routing for NSManagedObject class. You probably want to create a custom class, say MySyncEntity that holds the ivars you define in your mapping. Then, you create your mapping like this:
RKObjectMapping* mapping = [RKObjectMapping mappingForClass:[MySyncEntity class]];
....
[myManager setSerializationMIMEType:RKMIMETypeJSON];
[[myManager router] routeClass:[MySyncEntity class] toResourcePath:#"/sync"];
then you should be able to post your object to the API backend as JSON object.
Further clarification:
In this case, we want to post an array of NSManagedObject instances into a JSON based API. To do that we need to create a sync entity, that holds the objects in an array:
#interface MySyncEntity : NSObject {}
#property (nonatomic, retain) NSArray* mySyncArray;
...
#end
The mySyncArray will hold the payload we'd like to submit to the rest backend. Then, we create appropriate mapping for both NSManagedObject that will be sent in mySyncArray and the MySyncEntity entity itself.
RKObjectManager *manager = [RKObjectManager objectManagerWithBaseURL:kBaseUrl];
...
RKObjectMapping *mngObjMapping = [RKObjectMapping mappingForClass:[NSManagedObject class]];
[mngObjMapping mapKeyPath: #"time" toAttribute:#"time"];
[mngObjMapping mapKeyPath: #"recordLevel" toAttribute:#"recordLevel"];
.... //map as many properties as you wish
[[manager mappingProvider] setSerializationMapping:[mngObjMapping inverseMapping]
forClass:[NSManagedObject class]];
//now, we create mapping for the MySyncEntity
RKObjectMapping *syncEntityMapping = [RKObjectMapping mappingForClass:[MySyncEntity class]];
[syncEntityMapping mapKeyPath:#"mySyncArray" toRelationship:#"mySyncArray" withMapping:mngObjMapping];
[[manager mappingProvider] setSerializationMapping:[syncEntityMapping inverseMapping]
forClass:[MySyncEntity class]];
Now with the mappings defined we can post the object to the server
[manager postObject:mySyncInstance delegate:nil];
The contents of mySyncInstance array will be mapped according to mngObjMapping and sent to defined rest endpoint.
As a further clarification, I'd like to point out that in mja's answer the key thing is
[syncEntityMapping mapKeyPath:#"mySyncArray" toRelationship:#"mySyncArray" withMapping:mngObjMapping];
This says "the mySyncArray keypath is an array which contains objects that should be mapped according to mngObjMapping".