iOS RestKit issue: Invalid parameter not satisfying: responseDescriptors - ios

I am trying to use RestKit to retrieve a listing of events and I keep getting this:
2013-05-20 10:52:56.708 EventApp[3380:c07] I restkit:RKLog.m:34 RestKit logging initialized...
2013-05-20 10:52:56.773 EventApp[3380:c07] *** Assertion failure in -[RKObjectRequestOperation initWithRequest:responseDescriptors:], /Users/mitchell/Desktop/eventapp/take2/EventApp/Pods/RestKit/Code/Network/RKObjectRequestOperation.m:158
2013-05-20 10:52:56.774 EventApp[3380:c07] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: responseDescriptors'
I have been scratching my head for days on this one. As I have a fair amount of gaps in my iOS dev skills(about one project every year) it would greatly help if someone can just lead me in the right direction here using some laymen terms.
Please consider that I am looking to use enqueueObjectRequestOperation specifically for batching multiple requests. I have just pieced together bits of my code for translation here.
Here is what my datamodel looks like:
Here is the what the JSON file looks like:
[{
"id":1,
"farm_id":1,
"all_day": "NO",
"from": "2013-05-08T18:45:38Z",
"to": "2013-05-08T18:45:38Z",
"name": "event 1",
"desc": "some description",
"photo": "some.png",
"price": "price"
}]
Here is my code:
NSManagedObjectContext *context;
RKObjectManager *objectManager;
if (self.eventContext == nil) {
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"FarmApp" ofType:#"momd"]];
RKEntityMapping *entityMapping;
// NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
// Initialize the Core Data stack
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *eventPersistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(eventPersistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://sandbox.bm.com"]];
[RKObjectManager setSharedManager:objectManager];
[objectManager setRequestSerializationMIMEType:#"application/json"];
[objectManager setAcceptHeaderWithMIMEType:#"text/plain"];
objectManager.managedObjectStore = managedObjectStore;
entityMapping = [RKEntityMapping mappingForEntityForName:#"Event" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"eventID",
#"farm_id": #"farm",
#"all_day": #"allDay",
#"from": #"from",
#"to": #"to",
#"name": #"name",
#"desc": #"desc",
#"photo": #"photo",
#"price": #"price"
}];
RKResponseDescriptor *successDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:successDescriptor];
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:#"errors" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[objectManager addResponseDescriptor:errorDescriptor];
self.eventContext = managedObjectStore.mainQueueManagedObjectContext;
}
context = self.eventContext;
NSString* url = [NSString stringWithFormat:#"http://sandbox.bm.com/farmapp/%#.json", #"events"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:[objectManager responseDescriptors]];
[operation setCompletionBlockWithSuccess:nil failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Loaded this error: %#", [error localizedDescription]);
}];
NSArray *operations = [NSArray arrayWithObjects:operation, nil];
for (int i = 0; i < [operations count]; i++ ) {
[[RKObjectManager sharedManager] enqueueObjectRequestOperation:[operations objectAtIndex:i]];
}
Can someone out there help me?
Here is the final solution
if (self.eventContext == nil) {
NSManagedObjectContext *context;
RKObjectManager *objectManager;
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"FarmApp" ofType:#"momd"]];
RKEntityMapping *entityMapping;
// NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
// Initialize the Core Data stack
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *eventPersistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(eventPersistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://sandbox.bm.com"]];
[RKObjectManager setSharedManager:objectManager];
[objectManager setRequestSerializationMIMEType:#"application/json"];
[objectManager setAcceptHeaderWithMIMEType:#"text/plain"];
objectManager.managedObjectStore = managedObjectStore;
entityMapping = [RKEntityMapping mappingForEntityForName:#"Event" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"eventID",
//#"farm_id": #"farm",-->cannot create relationship this way
#"farm_id" : #"farmID",//farmID attribute needs to be added to Event's model
#"all_day": #"allDay",
#"from": #"from",
#"to": #"to",
#"name": #"name",
#"desc": #"desc",
#"photo": #"photo",
#"price": #"price"
}];
[entityMapping addConnectionForRelationship:#"farm" connectedBy:#"farmID"];
RKResponseDescriptor *successDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:#"events" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:successDescriptor];
RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:nil keyPath:#"errors" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];
[objectManager addResponseDescriptor:errorDescriptor];
self.eventContext = managedObjectStore.mainQueueManagedObjectContext;
context = self.eventContext;
NSString* url = [NSString stringWithFormat:#"http://sandbox.bm.com/farmapp/%#.json", #"events"];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
RKManagedObjectRequestOperation *operation = [objectManager managedObjectRequestOperationWithRequest:request managedObjectContext:managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
NSArray *operations = [NSArray arrayWithObjects:operation, nil];
for (int i = 0; i < [operations count]; i++ ) {
[[RKObjectManager sharedManager] enqueueObjectRequestOperation:[operations objectAtIndex:i]];
}
}

As #JoelH. suggests in one of his comments, you need to use RKManagedObjectRequestOperation instead of RKObjectRequestOperation.
For example :
RKManagedObjectRequestOperation *operation = [objectmanager managedObjectRequestOperationWithRequest:request managedObjectContext:managedObjectStore.mainQueueManagedObjectContext success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success");
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure");
}];
Besides, I think the way you are mapping
#"farm_id": #"farm"
is not correct.
If you want to build the relationship between Event and Farm, you need to use one of these methods :
relationshipMappingFromKeyPath:toKeyPath:withMapping:
or addConnectionForRelationship:connectedBy:
If the Farm object already exists and you only want to map the new Event, I would go for addConnectionForRelationship:connectedBy:
For example :
RKEntityMapping* eventMapping = [RKEntityMapping mappingForEntityForName:#"Event" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"eventID",
//#"farm_id": #"farm",-->cannot create relationship this way
#"farm_id" : #"farmID",//farmID attribute needs to be added to Event's model
#"all_day": #"allDay",
#"from": #"from",
#"to": #"to",
#"name": #"name",
#"desc": #"desc",
#"photo": #"photo",
#"price": #"price"
}];
[eventMapping addConnectionForRelationship:#"farm" connectedBy:#"farmID"];
It would also require to add a farmID attribute in your Event model, as RestKit does not allow relationship connection without intermediary attributes yet.

The RestKit docs (Mapping Without KVC) seem to imply that if you don't have a KVC label on the top level(e.g. events:[]), a pathPattern: is required for the parser to know which mapping to use. Since both your keyPath: and pathPattern: are nil for your successDescriptor, I have two suggestions:
If changing the JSON structure is possible, change the top level to { events:[...] } and change keyPath:nil to keyPath:#"events" to reflect this change.
If it's not possible, change pathPattern:nil to pathPattern:#"/farmapp" Notice, I set pathPattern: to match your resource URL. This second suggestion might not work if you have other types of resources branching from that URL as well.
Also, I noticed that your errorDescriptor uses the same mapping(entityMapping) as your successDescriptor. I don't know if that's what you intended, but if your error response is supposed to be some different error object, I suggest changing that.
Hope this helps!

Related

iOS - get objects from RESTful service with RestKit

I am trying to get data from my RESTful services. I get this code from some tutorials and I hope I get it right. I think I am just missing something. I get this:
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://www....com"]];
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
manager.managedObjectStore = managedObjectStore;
NSDictionary *parentObjectMapping = #{
#"lat" : #"latitude",
#"long" : #"longitude",
};
RKEntityMapping *cityMapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([City class]) inManagedObjectStore:managedObjectStore];
[cityMapping addAttributeMappingsFromDictionary:#{
#"name" : #"name",
#"country" : #"country",
#"population" : #"population",
}];
[cityMapping addAttributeMappingsFromDictionary:parentObjectMapping];
[manager addResponseDescriptorsFromArray:#[[RKResponseDescriptor responseDescriptorWithMapping:cityMapping
pathPattern:nil
keyPath:#"results"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]
]];
[manager getObjectsAtPath:#"/api/autocomplete?q=bos"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
}];
Last few lines I added because I think I was missing something like execute. Now when I run this I get error:
Unable to perform mapping: No `managedObjectContext` assigned.
How can I fix this? Did I make other things allright? Thanks
As the error already suggests: you are missing the managedObjectContext. Add it using [managedObjectStore createManagedObjectContexts]; (the line after creating the store itself)

POST with RestKit 0.20 - NSManagedObjectContext issue

I'm trying to make a POST request with RestKit, but when I call the postObject method of my RKObjectManager I get the following error :
Can only use -performBlockAndWait: on an NSManagedObjectContext that was created with a queue.
This error came when the method performBlockAndWait is called by the RKManagedObjectRequestOperation class.
Here is my code :
RKObjectMapping *responseMapping = [RKObjectMapping requestMapping];
[responseMapping addAttributeMappingsFromDictionary:#{
// ...
}];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
NSString *pathPattern = #"myPath";
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping method:RKRequestMethodPOST pathPattern:pathPattern keyPath:nil statusCodes:statusCodes];
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
[requestMapping addAttributeMappingsFromDictionary:#{
// ...
}];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[MyClass class] rootKeyPath:#"" method:RKRequestMethodPOST];
NSURL *baseURL = [NSURL URLWithString:#"http://192.168.1.1:8080"];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:baseURL];
[manager addRequestDescriptor:requestDescriptor];
[manager addResponseDescriptor:responseDescriptor];
NSManagedObjectModel *managedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
manager.managedObjectStore = managedObjectStore;
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"mySqliteDatabaseFile"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, #"Failed to add persistent store with error: %#", error);
[managedObjectStore createManagedObjectContexts];
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
// POST to create
#try {
[manager postObject:visitReport path:#"myPath" parameters:nil success:^( RKObjectRequestOperation *operation , RKMappingResult *mappingResult ) {
NSLog(#"Success");
} failure:^( RKObjectRequestOperation *operation , NSError *error ){
NSLog(#"Failure - %#",error);
}];
}
#catch (NSException *exception) {
NSLog(#"error - %#", exception);
}
I don't understand the problem with my context, any help is welcomed.
Thank you.
Ok finally I find the problem :
The object visitReport I tried to POST is not from the NSManagedObjectContext expected by RestKit.
To solve, I create a new object :
MyObject *visitReportContext = [NSEntityDescription insertNewObjectForEntityForName:#"tableName"
inManagedObjectContext:objectStore.mainQueueManagedObjectContext];
visitReportContext.Id = visitReport.Id
visitReportContext.title = visitReport.title
// etc..
Then, when I POST my new object, it works. But it's not very beautiful... How can I deal with my old object visitReport without create a new one in this "RestKit context" ?

How to Post to database via RestKit 0.20

I am trying to POST to an API using restkit.
When I press save post- I get an error showing an empty post and alert saying:
Expected status code in (200-299), got 422" UserInfo=0xb83ca20 {NSLocalizedRecoverySuggestion={"body":["can't be blank"]},
The post is displayed in the tableView but the text I entered doesn't make it to the database.
Any ideas why this might be? The usual problems I've seen are because people are missing parsing the data to json or because they lack a responseDescriptor - but I have this and I'm not getting the json error. It's just not retaining the text I enter.
Why is this?
My savePost method is like this
RKManagedObjectStore *objectStore = [[RKObjectManager sharedManager] managedObjectStore];
Post *post = [NSEntityDescription insertNewObjectForEntityForName:#"Post" inManagedObjectContext:objectStore.mainQueueManagedObjectContext];
[post setBody:self.postTextField.text];
[objectStore.mainQueueManagedObjectContext save:nil];
RKObjectManager *manager = [RKObjectManager sharedManager]; [manager postObject:self path:#"/posts.json" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"Success saving post");
// [MUser setCurrentUser:self];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failure saving post: %#", error.localizedDescription);
}];
And in my appDelegate I have this setup:
NSError *error = nil;
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"Markofresh" ofType:#"momd"]];
// NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
// Initialize the Core Data stack
[managedObjectStore createPersistentStoreCoordinator];
NSPersistentStore __unused *persistentStore = [managedObjectStore addInMemoryPersistentStore:&error];
NSAssert(persistentStore, #"Failed to add persistent store: %#", error);
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
// Set the default store shared instance
[RKManagedObjectStore setDefaultStore:managedObjectStore];
// Configure the object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"https://fierce.herokuapp.com"]];
objectManager.managedObjectStore = managedObjectStore;
[objectManager setRequestSerializationMIMEType:#"application/json"];
[objectManager setAcceptHeaderWithMIMEType:#"application/json"];
[RKObjectManager setSharedManager:objectManager];
//setup Post Entity map
RKEntityMapping *entityMapping = [RKEntityMapping mappingForEntityForName:#"Post" inManagedObjectStore:managedObjectStore];
[entityMapping addAttributeMappingsFromDictionary:#{
#"id": #"postID",
#"url": #"jsonURL",
#"body": #"body",
#"created_at": #"createdAt"}];
entityMapping.identificationAttributes = #[ #"postID" ];
[RKObjectManager sharedManager].requestSerializationMIMEType = RKMIMETypeJSON;
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:entityMapping pathPattern:#"/posts.json" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[entityMapping inverseMapping] objectClass:[Post class] rootKeyPath:#"/posts.json"];
[objectManager addRequestDescriptor:requestDescriptor];
I have seen other people get hung up on this and wonder if maybe AFNetworking might be a better choice for this kind of simple method- and there's more documentation on it as well.
I know what I'm trying to do is simple and I don't get what is causing the empty post. Any help would be greatly appreciated.
Should you be doing:
[manager postObject:post path:#"/posts.json" parameters:nil ...
So your issue is simply a typo?
Try turning on mapping trace logging so you can see what's happening:
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
And think about something like the Charles Proxy to show you exactly what's hitting the wire.

Restkit 0.20rc1 - Mapping Entity without KVC

So i am trying to mapping a JSON object without KVC with Restkit 0.20
The JSON whithout KVC
{
"created_at": "2013-03-11T22:13:05Z",
"facebookId": "2343434322",
"firstname": "testuser",
"id": 197,
"mail": "test#gmail.com",
"name": "test",
"phone": "098748394",
"sex": null,
"twitterId": null,
"updated_at": "2013-03-11T22:13:05Z",
"vehiculeDescription": "car",
"recommendCount": 0
}
My app delegate
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:WEBSERVICE]];
// Initialize managed object store
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:#"KojoClient" ofType:#"momd"]];
// NOTE: Due to an iOS 5 bug, the managed object model returned is immutable.
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
manager.managedObjectStore = managedObjectStore;
RKEntityMapping *utilisateurMapping =
[RKEntityMapping mappingForEntityForName:NSStringFromClass([Utilisateur class]) inManagedObjectStore:manager.managedObjectStore];
utilisateurMapping.identificationAttributes = #[#"remoteid"];
[utilisateurMapping addAttributeMappingsFromDictionary:#{
#"remoteid": #"id",
#"name": #"name",
#"firstname": #"firstname",
#"phone": #"phone",
#"facebookid": #"facebookId",
#"mail": #"mail",
#"vehiculeDescription" : #"vehiculeDescription",
#"recommendCount" : #"recommendCount",
#"created_at": #"created_at",
#"updated_at": #"updated_at",
#"twitterId": #"twitterId"
}];
/**
Register our mappings with the provider
*/
RKResponseDescriptor* utilisateursDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:[utilisateurMapping inverseMapping]
pathPattern:#"/utilisateurs"
keyPath:#""
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKResponseDescriptor* utilisateurDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:[utilisateurMapping inverseMapping]
pathPattern:#"/utilisateurs/:remoteid"
keyPath:#""
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKResponseDescriptor* facebookUtilisateurDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:[utilisateurMapping inverseMapping]
pathPattern:#"/face_utilisateurs/:facebookid"
keyPath:#""
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[manager addResponseDescriptorsFromArray:#[utilisateursDescriptor, utilisateurDescriptor, facebookUtilisateurDescriptor]];
// Serialize to JSON
manager.requestSerializationMIMEType=RKMIMETypeJSON;
/**
Complete Core Data stack initialization
*/
[managedObjectStore createPersistentStoreCoordinator];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"Application.sqlite"];
NSError *error;
NSPersistentStore *persistentStore = [managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:#{NSMigratePersistentStoresAutomaticallyOption:#YES, NSInferMappingModelAutomaticallyOption:#YES} error:&error];
NSAssert(persistentStore, #"Failed to add persistent store with error: %#", error);
// Create the managed object contexts
[managedObjectStore createManagedObjectContexts];
// Configure a managed object cache to ensure we do not create duplicate objects
managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];
The problem is when i want to get my objet with :
[[RKObjectManager sharedManager] getObjectsAtPath:path parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
if(![[mappingResult firstObject] isKindOfClass:[Utilisateur class]]) {
//Dont work
}
} nil];
The RKMappingResult object has no class.
Unknown class image
But the mapping work
Printing description of mappingResult->_keyPathToMappedObjects:
{
"" = {
"created_at" = "2013-03-11T22:13:05Z";
facebookid = 4567898765;
firstname = Test;
mail = "test#gmail.com";
name = TestName;
phone = 45678976587;
recommendCount = 0;
remoteid = 197;
"updated_at" = "2013-03-11T22:13:05Z";
vehiculeDescription = "test";
};
}
I don't understand why my object mapped has no class.
I have follow the Object Mapping Tutorial without KVO
And can't change the server JSON style.
Update 1
I try without the NSStringFromClass, dont work.
Why you are using [utilisateurMapping inverseMapping] for RKResponseDescriptor with RKEntityMapping? Maybe if you try:
RKResponseDescriptor* utilisateursDescriptor =
[RKResponseDescriptor responseDescriptorWithMapping:utilisateurMapping
pathPattern:#"/utilisateurs"
keyPath:#""
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

RestKit: How to batch multiple requests and get a response once they finish?

I just found out RestKit and it will be an important part of the app I'm doing. At the time, I was able to integrate it with the core data, but have not figured out the best way to send multiple GET requests.
What I need to do is:
Get data from the following addresses:
http://url.com/api/banner/
http://url.com/api/category/
http://url.com/api/link/
The URL will always be in the following format: http://url.com/api/SOMETHING/
Once all requests are finished, I would like to run a code (such as calling a new view controller). What would be the best way to do this?
At the moment, this is the code I'm using:
- (id)init
{
self = [super init];
if (self) {
[self setupConnector];
[self setupDatabase];
[self setupMappings];
[self sendRequests];
}
return self;
}
- (void)setupConnector
{
// Initialize RestKIT
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://baseURL"]];
self.managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[[NLCoreData shared] managedObjectModel]];
objectManager.managedObjectStore = self.managedObjectStore;
}
- (void)setupDatabase
{
NSString *storePath = [[NLCoreData shared] storePath];
NSError *error = nil;
NSPersistentStore *persistentStore = [self.managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:&error];
NSAssert(persistentStore, #"Failed to add persistent store with error: %#", error);
[self.managedObjectStore createManagedObjectContexts];
self.managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:self.managedObjectStore.persistentStoreManagedObjectContext];
}
- (void)setupMappings
{
RKObjectManager *objectManager = [RKObjectManager sharedManager];
// Mappings
// banner
RKEntityMapping *bannerMapping = [RKEntityMapping mappingForEntityForName:#"Banner" inManagedObjectStore:self.managedObjectStore];
[bannerMapping addAttributeMappingsFromDictionary:#{
#"title": #"title",
#"id": #"bannerID",
#"created_at": #"created_at",
#"image": #"image",
#"resource_uri": #"resource_uri",
#"updated_at": #"updated_at",
#"url": #"url"
}];
bannerMapping.identificationAttributes = #[ #"bannerID" ];
RKResponseDescriptor *bannerDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:bannerMapping
pathPattern:#"/api/v1/banner/"
keyPath:#"objects"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:bannerDescriptor];
// category
RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:#"Category" inManagedObjectStore:self.managedObjectStore];
[categoryMapping addAttributeMappingsFromDictionary:#{
#"name": #"name",
#"id": #"categoryID",
#"created_at": #"created_at",
#"resource_uri": #"resource_uri",
#"updated_at": #"updated_at",
#"active": #"active"
}];
categoryMapping.identificationAttributes = #[ #"categoryID" ];
RKResponseDescriptor *categoryDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:categoryMapping
pathPattern:#"/api/v1/category/"
keyPath:#"objects"
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:categoryDescriptor];
}
- (void)sendRequests
{
RKObjectManager *objectManager = [RKObjectManager sharedManager];
// Send Request
[objectManager getObjectsAtPath:#"/api/v1/banner/" parameters:nil success:^(RKObjectRequestOperation * operation, RKMappingResult *mappingResult) {
NSLog(#"SUCCESS: %#", mappingResult.array);
} failure: ^(RKObjectRequestOperation * operation, NSError * error) {
NSLog(#"FAILURE %#", error);
}];
// category
[objectManager getObjectsAtPath:#"/api/v1/category/" parameters:nil success:^(RKObjectRequestOperation * operation, RKMappingResult *mappingResult) {
NSLog(#"SUCCESS: %#", mappingResult.array);
} failure: ^(RKObjectRequestOperation * operation, NSError * error) {
NSLog(#"FAILURE %#", error);
}];
}
Any tips?
The RestKit solution would be this: instead of using the convenience method ObjectManager::getObjectsAtPath you will have to init all of your RKObjectRequestOperations manually and then use ObjectManager::enqueueBatchOfObjectRequestOperations:progress:completion: method to enqueue them.
Alternatively, and I think this is actually easier and cleaner solution, use dispatch groups as described in the accepted answer to this question.
NSURL *url1 = [NSURL URLWithString:#"http://baseURL.domain/api/banner/"];
NSMutableURLRequest *request2 = [NSMutableURLRequest requestWithURL:url1];
RKObjectRequestOperation *objectRequestOperation1 = [[RKObjectRequestOperation alloc] initWithRequest:request2 responseDescriptors:#[ ResponseDescriptor ]];
NSURL *url2 = [NSURL URLWithString:#"http://baseURL.domain/api/category/"];
NSMutableURLRequest *request2 = [NSMutableURLRequest requestWithURL:url2];
RKObjectRequestOperation *objectRequestOperation2 = [[RKObjectRequestOperation alloc] initWithRequest:request2 responseDescriptors:#[ ResponseDescriptor ]];
NSArray *requestArray = [NSArray arrayWithObjects:objectRequestOperation,objectRequestOperation1,objectRequestOperation2, nil];
[[RKObjectManager sharedManager] enqueueBatchOfObjectRequestOperations:requestArray progress:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
//
// Handle process indicator
//
NSLog(#"%lu",(unsigned long)totalNumberOfOperations);
} completion:^(NSArray *operations) {
//
// Remove blocking dialog, do next tasks
?

Resources