I have an API that I'm querying where when I query for a list of organizations I get an array of:
{
id: integer,
name: string
}
But I am also able to get details on each organization which returns a single object like:
{
id: integer,
name: string,
description: text,
visit_count: integer,
image_url: string
}
How would I set up the object(s) in RestKit for this?
You need to setup the following:
The Object with all the elements you described in your second block
An object manager
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:YOUR HOST NAME]];
objectManager.requestSerializationMIMEType=RKMIMETypeJSON;
A mapping object with all the elements in your object
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[YOUR CLASS class]];
The mapping for your object
[mapping addAttributeMappingsFromArray:#[#"id",
#"name",
#"description",
#"visit_count",
#"image_url"
]];
A response descriptor
RKResponseDescriptor *responseDesciptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method:RKRequestMethodAny pathPattern:OBJECT URL keyPath:YOUR KEY PATH statusCodes:nil];
Add the response descriptor to the object manager
[objectManager responseDesciptor];
Now you can hit up the server
[[RKObjectManager sharedManager] postObject:nil path:OBJECT URL parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
self.variable = [NSMutableArray arrayWithArray: mappingResult.array];
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"An Error Has Occurred" message:[error localizedDescription] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alertView show];
}];
Related
I am trying to call web service and upload image,
There is a problem in the mapping, and I have spent many hours on it without success. The error I am getting is:
Error Domain=org.restkit.RestKit.ErrorDomain Code=1001 "No mappable
object representations were found at the key paths searched."
UserInfo={NSLocalizedDescription=No mappable object representations
were found at the key paths searched., NSLocalizedFailureReason=The
mapping operation was unable to find any nested object representations
at the key paths searched: user The representation inputted to the
mapper was found to contain nested object representations at the
following key paths: message, success This likely indicates that you
have misconfigured the key paths for your mappings., keyPath=null,
DetailedErrors=( )}
and there method that call web service
[SVProgressHUD show];
[delegate.objectManager.HTTPClient.defaultHeaders setValue:#"application/x-www-form-urlencoded" forKey:#"content-type" ];
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[SignUpResponse class]]; //create response and request mapping
[responseMapping addAttributeMappingsFromDictionary:#{#"phone": #"phone",
#"device_type": #"device_type",
#"device_token": #"device_token",
#"type": #"type",
#"email": #"email",
#"identity": #"identity",
#"date": #"date",
#"status": #"status",
#"name": #"name",
#"activation": #"activation",
#"image": #"image",
#"id": #"id"
}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping
method:RKRequestMethodPOST
pathPattern:#"AgentRegister"
keyPath:#"user"
statusCodes:[NSIndexSet indexSetWithIndex:200]];
[delegate.objectManager.defaultHeaders setValue:#"application/x-www-form-urlencoded" forKey:#"content-type" ];
delegate.objectManager.requestSerializationMIMEType =RKMIMETypeFormURLEncoded;
[delegate.objectManager removeResponseDescriptor:responseDescriptor];
[delegate.objectManager addResponseDescriptor:responseDescriptor];
NSString *fcmToken = [FIRInstanceID instanceID].token;
SignUpRequest *signUpRequest = [[SignUpRequest alloc]init];
signUpRequest.phone = txtPhoneNumber.text;
signUpRequest.email = txtEmail.text;
signUpRequest.identity=txtIdOrCity.text;
signUpRequest.device_type=#"IOS";
signUpRequest.device_token=fcmToken;
signUpRequest.type=#"1";
UIImage *image = [UIImage imageNamed:#"Logo"];
// Serialize the Article attributes then attach a file
NSMutableURLRequest *request = [[RKObjectManager sharedManager] multipartFormRequestWithObject:signUpRequest method:RKRequestMethodPOST path:#"AgentRegister" parameters:nil constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFileData:UIImagePNGRepresentation(image)
name:#"image"
fileName:#"photo.png"
mimeType:#"application/x-www-form-urlencoded"];
}];
RKObjectRequestOperation *operation = [[RKObjectManager sharedManager] objectRequestOperationWithRequest:request success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
[SVProgressHUD dismiss];
if(mappingResult.array.count !=0){
[self performSegueWithIdentifier:#"goToVerify" sender:self];
}else{
}
[delegate.objectManager removeResponseDescriptor:responseDescriptor];
}failure:^(RKObjectRequestOperation *operation, NSError *error){
[SVProgressHUD dismiss];
NSLog(#"%#",error.description);
UIAlertController *alert = [UIAlertController alertControllerWithTitle:#".."
message:#"حدث خطاء ما .. حاول مرة اخري" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:#"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
}];
[alert addAction:okAction];
[self presentViewController:alert animated:YES completion:nil];
[delegate.objectManager removeResponseDescriptor:responseDescriptor];
}];
[[RKObjectManager sharedManager] enqueueObjectRequestOperation:operation];
}
This error is telling you that nothing was available at the user path. For instance, if your response is JSON, there would be no root key called user, only message and success:
{
"user": "<- This key doesnt exist",
"message": "<- There is something here",
"success": "<- There is also something here"
}
You most likely need to change your keyPath from user to something like success.user.
I have an API sitting at this url: https://evening-everglades-1560.herokuapp.com/api/v1/stocks/
I am trying to implement iOS RestKit with like so (this is in MasterViewController.m):
RKObjectMapping *stockMapping = [RKObjectMapping mappingForClass:[Stock class]];
[stockMapping addAttributeMappingsFromDictionary:#{#"stockId": #"id"}];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:stockMapping method:RKRequestMethodAny pathPattern:nil keyPath:#"" statusCodes:statusCodes];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"https://evening-everglades-1560.herokuapp.com/api/v1/stocks.json"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
Stock *stock = [result firstObject];
NSLog(#"mapped w stock: %#", stock);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"failed w error: %#", [error localizedDescription]);
}];
[operation start];
This is what is logged:
2016-01-17 16:42:08.233 Stocks[9415:1208281] W restkit.object_mapping:RKMapperOperation.m:99 Adding mapping error: No mappable values found for any of the attributes or relationship mappings
2016-01-17 16:42:08.234 Stocks[9415:1208308] I restkit.network:RKObjectRequestOperation.m:250 GET 'https://evening-everglades-1560.herokuapp.com/api/v1/stocks.json' (200 OK / 0 objects) [request=0.4798s mapping=0.0042s total=0.5528s]
2016-01-17 16:42:08.235 Stocks[9415:1208245] mapped w stock: (null)`
I am not sure of what to put for the pathPattern and keyPath.
Thanks in advance!
It is fixed thanks to wain inquiring about "you haven't given your object definition." I forgot to define submitter in my stock.h cocoa class.
Adding #property(nonatomic, strong) NSString *submitter; to stock.h fixed it.
RestKitObjectMapping Array off null objects
I want to map CapitalImage object in Capital images object property.
//------------------------ The mapping I try to
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class]
forMIMEType:#"text/html"];
RKObjectMapping *CapitalImageMap = [RKObjectMapping mappingForClass:[CapitalImage class]];
[CapitalImageMap addAttributeMappingsFromDictionary:#{
#"src": #"src"
}];
RKObjectMapping *CapitalMap = [RKObjectMapping mappingForClass:[Capital class]];
[CapitalMap addAttributeMappingsFromDictionary:#{
#"name": #"name",
#"text": #"text"
}];
[CapitalMap addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"images" toKeyPath:#"images" withMapping:CapitalImageMap]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:CapitalMap
method:RKRequestMethodAny
pathPattern:nil
keyPath:nil
statusCodes:statusCodes];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.a10073.de4.dp10.ru/icapitals/capital.php"]];
RKObjectRequestOperation *operation = [[RKObjectRequestOperation alloc] initWithRequest:request responseDescriptors:#[responseDescriptor]];
[operation setCompletionBlockWithSuccess:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
Capital *article = [result firstObject];
NSLog(#"Mapped the article: %# , %#", article.name,article.images.description);
} failure:^(RKObjectRequestOperation *operation, NSError *error) { NSLog(#"Failed with error: %#", [error localizedDescription]); }];
[operation start];
I get this result
2013-09-27 23:20:49.028 iCapitals v2[5099:c07] Mapped the article: London , (
(null),
(null),
(null),
)
LOGS - http://www.a10073.de4.dp10.ru/icapitals/consoleresult.txt
Please check the code and tell what i do wrong, Thanks!!!
Your mappings look correct. The log shows the mapping proceeding correctly. The issue appears to be with the CapitalImage class. Why is it giving a nil description? It could be that that is the only problem. So your log of the array is a list of nil, but the objects do exist.
Try logging the src of each objects. Are you seeing other issues? Did you implement the description method?
Hello and thanks in advance for your help. I've been looking but couldn't find an answer for this. I've only been programing for iOS for a week.
So far, all the connections to the web services are functioning and I've created a class and methods to do those calls. I'm making a standard login, user enters login info, the app passes those values to the web service and it returns a bool value depending if the info matches anything on the database. After that, the app gets the return value and it moves to the next screen or shows an error alert. Or at least that's what I'm aiming for.
The problem is that, the conditional is being executed before the rest call is made or the response parsed and I'm not having much luck finding a solution. I've read about asynchronous and synchronous calls but hadn't have much luck at implementing them.
This is the call code:
//Class that has the methods for calling the web services
__restObj = [[restCalls alloc] init];
bool login = [__restObj restLogin:user passwd:pass];
if (login) {
[self performSegueWithIdentifier:#"adminLogin" sender:self];
}
else{
UIAlertView*alert = [[UIAlertView alloc] initWithTitle:#"Error" message:#"Incorrect group name or password." delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[alert show];
}
The conditional in being performed before the actual POST occurs and there for is always false.
This is my method:
- (bool)restLogin:(NSString*)user passwd:(NSString*)pass{
// Load the object model via RestKit
RKObjectManager *objectManager = [RKObjectManager sharedManager];
groupInfo *gi = [[groupInfo alloc] init];
gi.gName = user;
gi.pass = pass;
RKObjectMapping *userInfoMapping = [RKObjectMapping requestMapping];
[userInfoMapping addAttributeMappingsFromDictionary:#{#"gName": #"groupName",#"pass":#"pass"}];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:userInfoMapping
objectClass:[groupInfo class]
rootKeyPath:nil];
[objectManager addRequestDescriptor:requestDescriptor];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager postObject:gi
path:#"adminLoginIos"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSArray* statuses = [mappingResult array];
NSLog(#"Loaded statuses: %#", statuses);
_result = [statuses objectAtIndex:0];
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Hit error: %#", error);
}
];
return _result;
}
Thanks in advance and keep in mind that I'm really new at this so I appreciate your help and if my code is not the best please tell me so.
Regards,
ChmlGr
You need to pass in a block and then inside the success callback, block return the _result.
An example based on your structure would be something like:
-(void) restLogin:(NSString*)user passwd:(NSString*)pass block:(void (^)(id))block {
// Load the object model via RestKit
RKObjectManager *objectManager = [RKObjectManager sharedManager];
groupInfo *gi = [[groupInfo alloc] init];
gi.gName = user;
gi.pass = pass;
RKObjectMapping *userInfoMapping = [RKObjectMapping requestMapping];
[userInfoMapping addAttributeMappingsFromDictionary:#{#"gName": #"groupName",#"pass":#"pass"}];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:userInfoMapping
objectClass:[groupInfo class]
rootKeyPath:nil];
[objectManager addRequestDescriptor:requestDescriptor];
objectManager.requestSerializationMIMEType = RKMIMETypeJSON;
[objectManager postObject:gi
path:#"adminLoginIos"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSArray* statuses = [mappingResult array];
NSLog(#"Loaded statuses: %#", statuses);
_result = [statuses objectAtIndex:0];
block(_result);
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Hit error: %#", error);
block(nil);
}
];
}
Your call to that method would be something like:
[__restObj restLogin:user passwd:pass block:^(id obj) {
// do something here to translate that object into a BOOL and check value
}];
I don't use RestKit, so I can't verify this is exactly what you need, but it should get you on the right path. That said, if you wanted to check out AFNetworking, I wrote a NetworkClient wrapper that I don't mind sharing.
So I am trying to grab information in JSON from my rails app with RestKit
My code to do so is like so:
App Delegate
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Initialise RestKit
NSURL *URL = [NSURL URLWithString:#"https://myapp.dev"];
AFHTTPClient* client = [[AFHTTPClient alloc] initWithBaseURL:URL];
//Enable Activity Indicator Spinner
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
[client setDefaultHeader:#"Accept" value:RKMIMETypeJSON];
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
RKObjectMapping *eventMapping = [RKObjectMapping mappingForClass:[Info class]];
[infoMapping addAttributeMappingsFromDictionary:#{
#"sample":#"sample",
#"sample_1":#"sample_1"
}];
RKResponseDescriptor *infoDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:infoMapping
pathPattern:#"/info"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:infoDescriptor];
}
View File
- (void)loadInfo
{
RKObjectManager *objectManager = [RKObjectManager sharedManager];
[objectManager getObjectsAtPath:#"/info"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSArray *info = [mappingResult array];
NSLog(#"Loaded info: %#", info);
_info = info;
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error getting into"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
NSLog(#"Hit error: %#", error);
}];
}
The problem is. On the log output, RestKit tells me it maps everything successfully. But then when I attempt to view the object with both the method to log in the view file and with the debugger using po I get the following
374 Finished performing object mapping. Results: {
"<null>" = "<Info: 0xa291b30>";
}
I can't view the object and with breakpoints it shows up as:
I've been struggling with this for a few days and I'm not sure what else to try. Any help would be greatly appreciated
I ran into a similar problem. I'm not too sure why, but when I did the following it fixed it.
- (void)loadInfo
{
RKObjectManager *objectManager = [RKObjectManager sharedManager];
[objectManager getObjectsAtPath:#"/info"
parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSArray *info = [mappingResult array];
NSLog(#"Loaded info: %#", info);
_info = info;
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error getting into"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
NSLog(#"Hit error: %#", error);
}];
}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//Initialise RestKit
NSURL *URL = [NSURL URLWithString:#"https://myapp.dev"];
AFHTTPClient* client = [[AFHTTPClient alloc] initWithBaseURL:URL];
//Enable Activity Indicator Spinner
[AFNetworkActivityIndicatorManager sharedManager].enabled = YES;
[client setDefaultHeader:#"Accept" value:RKMIMETypeJSON];
RKObjectManager *objectManager = [[RKObjectManager alloc] initWithHTTPClient:client];
RKObjectMapping *eventMapping = [RKObjectMapping mappingForClass:[Info class]];
[infoMapping addAttributeMappingsFromDictionary:#{
#"sample":#"sample",
#"sample_1":#"sample_1"
}];
RKResponseDescriptor *infoDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:infoMapping
pathPattern:#"/info/:id"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:infoDescriptor];
}
When you load an object representation that does not have a nesting keyPath, RestKit stores the mapped objects under the [NSNull null] key within the dictionary (since nil is not a valid dictionary key). You can retrieve the mapping results either by calling firstObject, array, or dictionary on the RKMappingResult object to access the mapped objects.
I see a follow-up question about mapping an array to a single object... what does your JSON look like and how are you trying to represent it?
RKResponseDescriptor *infoDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:infoMapping
pathPattern:nil
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];