NSLocalizedDescription=Expected status code in (200-299), got 422} - ios

I'm trying to make a ad post . I Set everything up as I thought it would be right however when I click the boson "cadastrar anuncio" it returns this error "got 422". already researched about the error however could not fix at all.
someone here has gone through this?
this is my web service
#import "JVWebService.h"
#import <RestKit/RestKit.h>
#import "AppDelegate.h"
#import "JVUtils.h"
#import "Ads.h"
static NSString *kServerURL = #"http://localhost:3000";
#interface JVWebService ()
#property (strong, nonatomic) RKObjectManager *restKitObjectManager;
#property (strong, nonatomic) NSDictionary *adAttributes;
#property (strong, nonatomic) NSDictionary *postAdAttributes;
#property (strong, nonatomic) NSDictionary *userAttributes;
#property (strong, nonatomic) NSDictionary *postUserAttributes;
#end
#define kSuccessStatusCode RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)
#implementation JVWebService
+ (instancetype)sharedService {
static JVWebService *sharedService = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedService = [[self alloc] init];
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
sharedService.restKitObjectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:kServerURL]];
[sharedService.restKitObjectManager.HTTPClient setAuthorizationHeaderWithUsername:[[[AppDelegate sharedDelegate] currentUser] email]
password:[[[AppDelegate sharedDelegate] currentUser] password]];
});
return sharedService;
}
#pragma mark - User
- (void)getUserForEmail:(NSString *)email andPassword:(NSString *)password {
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:User.class];
[objectMapping addAttributeMappingsFromDictionary:self.userAttributes];
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
[requestMapping addAttributeMappingsFromDictionary:self.postUserAttributes];
NSString *path = #"/users/sign_in.json";
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping
objectClass:User.class
rootKeyPath:#"user"
method:RKRequestMethodAny];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:objectMapping
method:RKRequestMethodAny
pathPattern:path
keyPath:#"user"
statusCodes:kSuccessStatusCode];
[self.restKitObjectManager addRequestDescriptor:requestDescriptor];
[self.restKitObjectManager addResponseDescriptor:responseDescriptor];
User *user = [User new];
user.email = email;
user.password = password;
[[NSUserDefaults standardUserDefaults] setObject:[[NSUUID UUID] UUIDString] forKey:#"authencity_token"];
NSDictionary *params = #{#"authenticity_token" : [[NSUserDefaults standardUserDefaults] objectForKey:#"authencity_token"]};
[self.restKitObjectManager.HTTPClient setAuthorizationHeaderWithUsername:email password:password];
[self.restKitObjectManager postObject:user path:path parameters:params success:^(RKObjectRequestOperation *operation,
RKMappingResult *result){
User *user = (User *)result.array.firstObject;
user.password = password;
[[AppDelegate sharedDelegate] login:user];
[[AppDelegate sharedDelegate] setLoggedViaFacebook:NO];
if ([self.serviceDelegate respondsToSelector:#selector(successfulRequestDidReturnObject:)])
[self.serviceDelegate successfulRequestDidReturnObject:user];
} failure:^(RKObjectRequestOperation *operation, NSError *error){
RKLogError(#"Operation failed with error: %#", error);
if ([self.serviceDelegate respondsToSelector:#selector(requestDidFailWithError:)])
[self.serviceDelegate requestDidFailWithError:error];
}];
[self.restKitObjectManager removeResponseDescriptor:responseDescriptor];
}
- (void)postAd:(Ads *)ad {
NSString *path = #"/ads.json";
RKObjectMapping *objectMapping = [RKObjectMapping mappingForClass:Ads.class];
[objectMapping addAttributeMappingsFromDictionary:self.adAttributes];
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
[requestMapping addAttributeMappingsFromDictionary:self.postAdAttributes];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping
objectClass:Ads.class
rootKeyPath:#"ad"
method:RKRequestMethodAny];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:objectMapping
method:RKRequestMethodAny
pathPattern:path
keyPath:#"ad"
statusCodes:kSuccessStatusCode];
[self.restKitObjectManager addRequestDescriptor:requestDescriptor];
[self.restKitObjectManager addResponseDescriptor:responseDescriptor];
NSMutableURLRequest *urlRequest = [self.restKitObjectManager multipartFormRequestWithObject:ad method:RKRequestMethodPOST path:path parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
// NSArray *photosArray = ad.photos[0];
// for(int i = 0; i < photosArray.count; i++) {
//
// NSString *name = [NSString stringWithFormat:#"ad[photos_attributes][%i][picture]", i];
// NSString *fileName = [NSString stringWithFormat:#"photo%i.jpg", i];
// [formData appendPartWithFileData:UIImagePNGRepresentation(photosArray[i])
// name:name
// fileName:fileName
// mimeType:#"image/jpg"];
// }
}];
RKObjectRequestOperation *operation = [self.restKitObjectManager objectRequestOperationWithRequest:urlRequest
success:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
if ([self.serviceDelegate respondsToSelector:#selector(successfulRequestDidReturnObject:)])
[self.serviceDelegate successfulRequestDidReturnObject:nil];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
if ([self.serviceDelegate respondsToSelector:#selector(requestDidFailWithError:)])
[self.serviceDelegate requestDidFailWithError:error];
}];
[self.restKitObjectManager enqueueObjectRequestOperation:operation];
[self.restKitObjectManager removeRequestDescriptor:requestDescriptor];
[self.restKitObjectManager removeResponseDescriptor:responseDescriptor];
}
- (NSDictionary *)adAttributes {
return #{
#"id" : #"_id",
#"title" : #"title",
#"price" : #"price",
#"local" : #"local",
#"description" : #"especification"
// #"categories" : #"categories",
// #"photos" : #"photos",
// #"latitude" : #"latitude",
// #"longitude" : #"longitude"
};
}
- (NSDictionary *)postAdAttributes {
return #{
#"_id" : #"id",
#"title" : #"title",
#"price" : #"price",
#"local" : #"local",
#"especification" : #"description"
// #"categories" : #"category_ids",
// #"user_id" : #"user_id",
// #"latitude" : #"latitude",
// #"longitude" : #"longitude"
};
}
- (NSDictionary *)userAttributes {
return #{
#"id" : #"_id",
#"email" : #"email",
#"name" : #"name",
#"avatar" : #"profileImageUrl",
#"phone" : #"phone",
#"password" : #"password",
#"contact_pref" : #"communicationPreference",
#"products_alerts" : #"productsAlerts"
};
}
- (NSDictionary *)postUserAttributes {
return #{
#"_id" : #"id",
#"email" : #"email",
#"name" : #"name",
#"phone" : #"phone",
#"password" : #"password",
#"password" : #"password_confirmation",
#"communicationPreference" : #"contact_pref"
};
}
#end
this is my NewAdViewController:
#import "NewAdViewController.h"
#import "Ads.h"
#import "JVUtils.h"
#import "JVWebService.h"
#import "AppDelegate.h"
#interface NewAdViewController ()
#end
#implementation NewAdViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (IBAction)signUp:(id)sender {
if (self.titleField.text.length <= 0) {
[JVUtils showMessage:#"Falta algo ae eem =D =D fdp." withTitle:#"Opa!"];
} else if (self.priceField.text.length <= 0) {
[JVUtils showMessage:#"Falta algo ae eem =D =D fdp" withTitle:#"Opa!"];
} else if (self.localField.text.length <= 0) {
[JVUtils showMessage:#"Falta algo ae eem =D =D fdp" withTitle:#"Opa!"];
} else if (self.descriptionField.text.length <= 0) {
[JVUtils showMessage:#"Falta algo ae eem =D =D fdp" withTitle:#"Opa!"];
} else {
Ads *newAd = [Ads new];
newAd.title = self.titleField.text;
newAd.price = self.priceField.text;
newAd.local = self.localField.text;
newAd.especification = self.descriptionField.text;
[[JVWebService sharedService] setServiceDelegate:self];
[[JVWebService sharedService] postAd:newAd];
}
}
- (void)successfulRequestDidReturnObject:(NSObject *)object {
[JVUtils showMessage:#"Anuncio cadastrado =D" withTitle:#"hadoukeeeen !"];
[[AppDelegate sharedDelegate] setCurrentUser:(User *)object];
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)requestDidFailWithError:(NSError *)error {
[JVUtils showMessage:error.localizedDescription withTitle:#"Errohue"];
}
-(void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
}
#end
Here is the detail from the server log
Started POST "/ads.json" for 127.0.0.1 at 2015-03-03 18:06:15 -0300
Processing by AdsController#create as JSON Parameters:
{"ad"=>{"description"=>"ewewe", "id"=>"", "local"=>"ew",
"price"=>"25", "title"=>"titulp"}} User Load (0.6ms) SELECT users.*
FROM users WHERE users.id = 2 ORDER BY users.id ASC LIMIT 1
Unpermitted parameters: id (0.2ms) BEGIN (0.6ms) ROLLBACK Completed
422 Unprocessable Entity in 10ms (Views: 0.3ms | ActiveRecord: 1.4ms)

Status code 422 indicates that your data was incorrect in some way - the request was well formed but the data couldn't be processed.
Looking at the log from the server you can see that id is empty and there is an error message Unpermitted parameters: id
You need to determine why id is empty and correct this before you send a request.

Related

Mapping an object to CoreData with 2 classes

So this is the first time i'm trying to map objects into CoreData, I think I got it right, but I have few issues. First of all, I just don't know if I'm mapping it the right way and the second one is that I get a success response but without objects mapped.
I have 2 objects DbRestError & DbRestCategory. DbRestError contain the error from the server and DbRestCategory contain the category itself. the are both coming back from the same response but RestKit seems unable to map them.
Those are the objects:
DbRestError
#interface DbRestError : NSManagedObject
#property (nonatomic, retain) NSNumber * statusCode;
#property (nonatomic, retain) NSString * errorTitle;
#end
DbRestCategory
#interface DbRestCategory : NSManagedObject
#property (nonatomic, retain) NSString * title;
#property (nonatomic, retain) NSNumber * idNum;
#end
This is how I initialize my CoreData with RestKit:
- (void)setup
{
self.objectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:#"database.sqlite"];
NSLog(#"Setting up store at %#", path);
[self.objectStore addSQLitePersistentStoreAtPath:path
fromSeedDatabaseAtPath:nil
withConfiguration:nil
options:#{ NSInferMappingModelAutomaticallyOption: #YES, NSMigratePersistentStoresAutomaticallyOption: #YES }
error:nil];
[self.objectStore createManagedObjectContexts];
}
This is how I initialize my RestKit client:
- (void)initRestClient
{
NSURL *baseURL = [NSURL URLWithString:kWebServiceBaseURL];
self.manager = [RKObjectManager managerWithBaseURL:baseURL];
[self.manager setRequestSerializationMIMEType:RKMIMETypeJSON];
[self.manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[self.manager addResponseDescriptorsFromArray:[RKObjectManager sharedManager].responseDescriptors];
[self.manager addRequestDescriptorsFromArray:[RKObjectManager sharedManager].requestDescriptors];
[self.manager.HTTPClient.operationQueue setMaxConcurrentOperationCount:MAX_CONCURRENT_OPERATION_COUNT];
[self.manager setManagedObjectStore:[[MainDb sharedDb] objectStore]];
[RKObjectManager setSharedManager:self.manager];
self.requestMethod = RKRequestMethodGET;
self.statusCode = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKRoute *categoriesRoute = [RKRoute routeWithClass:[DbRestCategory class] pathPattern:kGetCategories method:self.requestMethod];
categoriesRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:categoriesRoute];
// ##yosi -- Error Mapping
//
//
RKEntityMapping *errorMapping = [RKEntityMapping mappingForEntityForName:#"DbRestError" inManagedObjectStore:[[MainDb sharedDb] objectStore]];
[errorMapping addAttributeMappingsFromDictionary:#{ #"statusCode" : #"statusCode", #"description" : #"errorTitle" }];
// ##yosi -- Categories Mapping
//
//
RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:#"DbRestCategory" inManagedObjectStore:[[MainDb sharedDb] objectStore]];
[categoryMapping addAttributeMappingsFromDictionary:#{ #"id" : #"idNum", #"name" : #"title" }];
RKObjectMapping *categoriesMapping = [RKObjectMapping mappingForClass:[RestCategories class]];
[categoriesMapping addRelationshipMappingWithSourceKeyPath:#"categories" mapping:categoryMapping];
[categoriesMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"error" toKeyPath:#"error" withMapping:errorMapping]];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:categoriesMapping
method:self.requestMethod
pathPattern:kGetCategories
keyPath:nil
statusCodes:self.statusCode]];
}
This is how I'm doing the request itself:
[[RKObjectManager sharedManager] getObject:[[DbRestCategory alloc] init] path:nil parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
This is how the JSON looks like:
{
error: {
statusCode: 10,
description: "success"
},
categories: [
{
id: "3",
name: "cate 3"
},
{
id: "4",
name: "cate 4"
},
{
id: "5",
name: "cate 5"
},
{
id: "1",
name: "cate 1"
},
{
id: "6",
name: "cate 6"
},
{
id: "2",
name: "cate 2"
}
]
}
Can someone please help me to understand why i'm getting a response without any objects?
Try the request mapping like this,
// Request Mapping
// Map error
RKEntityMapping *errorMapping = [RKEntityMapping mappingForEntityForName:#"DbRestError" inManagedObjectStore:[[MainDb sharedDb] objectStore]];
[errorMapping addAttributeMappingsFromDictionary:#{ #"statusCode" : #"statusCode", #"description" : #"errorTitle" }];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:self.requestMethod pathPattern:kGetCategories keyPath:#"error" statusCodes:self.statusCode]];
// Map Category
RKEntityMapping *categoryMapping = [RKEntityMapping mappingForEntityForName:#"DbRestCategory" inManagedObjectStore:[[MainDb sharedDb] objectStore]];
[categoryMapping addAttributeMappingsFromDictionary:#{ #"id" : #"idNum", #"name" : #"title" }];
[[RKObjectManager sharedManager] addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:categoriesMapping method:self.requestMethod pathPattern:kGetCategories keyPath:#"categories" statusCodes:self.statusCode]];

RestKit Can't Map

I can not seem to figure out how to map the following JSON, I am trying to map the hostedLargeUrl from the response. I am not sure what to do for this issue, and would like to apologize if my info is not detailed enough. Not too sure what type of details you would need.
Thank you in advance.
images: [
{
imageUrlsBySize: {
90: "http://lh4.ggpht.com/ZXiwjS55Zk7oBu6GWaVr0HAqIPKumXwBfGtzsCWEFdrJSOXiCcC-I3TpUwrXBnP_DPNuBm-ib-4-3aXbs4mfXA=s90-c",
360: "http://lh4.ggpht.com/ZXiwjS55Zk7oBu6GWaVr0HAqIPKumXwBfGtzsCWEFdrJSOXiCcC-I3TpUwrXBnP_DPNuBm-ib-4-3aXbs4mfXA=s360-c"
},
hostedLargeUrl: "http://i.yummly.com/Pasta-with-garlicky-broccoli-rabe-305651-270310.l.jpg",
hostedSmallUrl: "http://i.yummly.com/Pasta-with-garlicky-broccoli-rabe-305651-270310.s.jpg"
}
Here is my code:
+ (RKMapping *)recipeDetailMapping
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[RecipeDetails class]];
[mapping addAttributeMappingsFromDictionary:#{
#"attribution.text" : #"attributionText",
#"images.hostedLargeUrl" : #"images"
}];
[mapping addAttributeMappingsFromArray:#[#"ingredientLines",
#"name",
#"totalTime",
]];
return mapping;
}
RecipeDetails
#property (nonatomic, copy) NSArray *ingredientLines;
#property (nonatomic, copy) NSString *name;
#property (nonatomic, copy) NSString *totalTime;
#property (nonatomic, copy) NSString *attributionText;
#property (nonatomic, copy) NSString *images;
Last bit of code
- (void)loadRecipeDetails
{
NSIndexSet *statusCodeSet = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKMapping *mapping = [MappingProvder recipeDetailMapping];
NSString *resourcePath = [NSString stringWithFormat:#"/v1/api/recipe/%#", self.recipeInfo.recipeId];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping
method:RKRequestMethodGET
pathPattern:resourcePath
keyPath:nil
statusCodes:statusCodeSet];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.yummly.com/v1/api/recipe/%#?_app_id=%#&_app_key=%#&requirePictures=true", self.recipeInfo.recipeId
,Yummly_APP_ID , Yummly_API_kEY ]];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request
responseDescriptors:#[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
self.recipeData = mappingResult.array;
[self updateUI];
[SVProgressHUD dismiss];
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
NSLog(#"Response: %#", operation.HTTPRequestOperation.responseString);
[SVProgressHUD showErrorWithStatus:#"Request Failed"];
}];
[operation start];
}
The source data is in an array and you need to deal with that in some way.
Option 1.
Change the property to NSArray *images;
Option 2.
Add a custom method setImageArray: and implement it to extract the first image and store it. Then change the mapping to use a destination key of imageArray.
Other options really require a different object graph...

Coercing NSNull value to nil in shouldSetValue:atKeyPath restkit

i'm having a web service that that collects the company names and phone numbers from the database. But sometimes a phone number is not provided. When i try to map the phone number to the object with restkit 'im getting a warning that value is nil sometimes. then i get the warning message:
Coercing NSNull value to nil in shouldSetValue:atKeyPath: -- should be fixed.
any suggestions how to map nil to NSNull?
this is my header file of my customerrealtion class (.h):
#import <Foundation/Foundation.h>
#import <RestKit/RestKit.h>
#interface CustomerRelation : NSObject
#pragma private fields
#property (nonatomic, copy) NSString *companyName;
#property (nonatomic, copy) NSString *phoneNumber;
#end
implementation file of customer relation class (.m)
#import "CustomerRelation.h"
#implementation CustomerRelation
-(BOOL)ValidatecompanyName:(id*)ioValue error:(NSError **)outError {
NSLog(#"error");
}
-(BOOL)validatephoneNumber:(id *)ioValue error:(NSError **)outError {
if (*ioValue == nil) {
if (outError != NULL) {
}
return NO;
}
return YES;
}
#end
this is where i do the mapping:
- (void)viewDidAppear:(BOOL)animated{
RKObjectManager * client = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://127.0.0.1"]];
RKObjectMapping *articleMapping = [RKObjectMapping requestMapping];
[articleMapping addAttributeMappingsFromDictionary:#{#"Companyname": #"companyName",
#"Phonenumber": #"phoneNumber"}];
RKResponseDescriptor *rkresponsedesc = [RKResponseDescriptor responseDescriptorWithMapping:articleMapping method:RKRequestMethodGET pathPattern:nil keyPath:#"customers" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[client addResponseDescriptor:rkresponsedesc];
NSMutableURLRequest *request = [client requestWithObject:nil method:RKRequestMethodGET path:#"test.php" parameters:nil];
RKObjectRequestOperation *operation = [client objectRequestOperationWithRequest:request
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
[self mappingSuccess:mappingResult];
} failure: ^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failed with error: %#", [error localizedDescription]);
}];
[client enqueueObjectRequestOperation:operation];
MainViewController *viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"mainViewController"];
[self.navigationController pushViewController:viewController animated:YES];
}
- (void)mappingSuccess:(RKMappingResult*)mappingResult
{
NSLog(#"Success block: %#", mappingResult);
}
Seeing that error I guess you're using an old version of RestKit and that you should update.
That said you should be able to tie into this with KVC validation which RestKit supports. If you implement validateValue:forKey:error: on your destination model object you can verify and edit the value being set for any key.
i finally found why the validate methods were never called.
the error was in the line
RKObjectMapping *customerRelationMapping = [RKObjectMapping requestMapping];
what should get the class instead:
RKObjectMapping *customerRelationMapping = [RKObjectMapping mappingForClass:[Article class]];

this class is not key value coding-compliant for the key Text using RestKit v0.20.0

For 2 days now, I've been trying to find out why I'm getting the error using iOS 6.1.3 with Xcode 4.6.2 and RestKit 0.20.0:
"...this class is not key value coding-compliant for the key Text."
The strange part is that I can receive (GET) the JSON object fine. The error happens when I create my sample SignalMessage object and then try to PUT it back to the server.
The JSON is as follows:
{"Text":"New Message","HasMessage":"true"}
The SignalMessage object looks like this:
#import <Foundation/Foundation.h>
#interface SignalMessage : NSObject {
}
#property (nonatomic, copy) NSString *signalText;
#property (nonatomic, retain) NSNumber *isHasMessage;
#end
And the implementation like this:
#import "SignalMessage.h"
#implementation SignalMessage
#synthesize isHasMessage, signalText;
#end
My correctly working getMessage function looks like this:
- (IBAction)getMessage:(id)sender;
{
NSLog(#"%#", #"Getting message... ");
NSURL *url = [NSURL URLWithString:#"http://ec2-54-243-148-145.compute-1.amazonaws.com/TabletPractice/api/signal?clientIdentifier=2"];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:url];
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[SignalMessage class]];
[responseMapping addAttributeMappingsFromDictionary:#{#"Text":#"signalText", #"HasMessage": #"isHasMessage"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[manager addResponseDescriptor:responseDescriptor];
[manager getObject:nil path:#"" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result)
{
NSArray *theresults = [result array];
for (SignalMessage *item in theresults) {
self.txtMessage.text = item.signalText;
[self hideControls];
}
} failure:^(RKObjectRequestOperation * operation, NSError * error)
{
NSLog (#"Server WS call failure: operation: %# \n\nerror: %#", operation, error);
}];
}
And here is the sendClicked message that gives me grieve:
- (IBAction)btnSendClicked:(id)sender;
{
if ([txtMessage.text length] < 1)
return;
NSURL *url = [NSURL URLWithString:#"http://ec2-54-243-148-145.compute-1.amazonaws.com/TabletPractice/api/signal?clientIdentifier=2"];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:url];
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
[requestMapping addAttributeMappingsFromDictionary:#{#"Text":#"signalText", #"HasMessage": #"isHasMessage"}];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping
objectClass:[SignalMessage class]
rootKeyPath:#""];
[manager addRequestDescriptor:requestDescriptor];
SignalMessage *newMessage = [[SignalMessage alloc] init];
newMessage.signalText = #"Test Message";
BOOL isMsg = TRUE;
NSNumber *boolAsNumber = [NSNumber numberWithBool:isMsg];
newMessage.isHasMessage = boolAsNumber;
[manager putObject:newMessage path:#"" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
NSLog(#"We object mapped the response with the following result: %#", result);
} failure:^(RKObjectRequestOperation * operation, NSError * error)
{
NSLog (#"Server WS call failure: operation: %# \n\nerror: %#", operation, error);
}];
[self hideControls];
}
At this point, I'm at a loss.
Please add a inverse mapping to your RKRequestDescriptor in your btnSendClicked method like below:
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor
requestDescriptorWithMapping:[requestMapping inverseMapping]
objectClass:[SignalMessage class]
rootKeyPath:#""];

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