I've got a problem with a POST-Mappping in RestKit. Basically my application needs to send a JSON-file to a server which expects the JSON to look exactly like the following example:
{
"ddata": {
"mLoad": {
"value": 13,
"unit": "%"
},
"cLoad": {
"value": 25,
"unit": "%"
}
},
"dm": "0815",
"vin": "VAPP",
"ts": "2014-09-24"
}
Unfortunately I'm not able to create a Mapping with RestKit which generates me a JSON that matches this format. Here's how the JSON looks at the moment:
{
"ddata" : [
{
"mLoad" : {
"unit" : "%",
"value" : "25"
}
},
{
"cLoad" : {
"unit" : "%",
"value" : "37"
}
}
],
"ts" : "2014-09-24",
"vin" : "VAPP",
"dm" : "0815"
}
As you can see in the result the ddata stuff is written as an array. Furthermore the outer { } of each "object" is too much.
Following my classes and the Mapping:
Mapping Class
#interface TopMapping : NSObject
#property NSString *dm;
#property NSString *vin;
#property NSString *ts;
#property NSSet *ddata;
#end
SubMapping Class
#interface SubMapping : NSObject
#property NSString *object;
#property NSString *value;
#property NSString *unit;
#end
Actual mapping
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[TopMapping class]];
[mapping addAttributeMappingsFromDictionary:#{
#"dm": #"dm",
#"vin": #"vin",
#"ts": #"ts"
}];
RKObjectMapping *subMapping = [RKObjectMapping mappingForClass:[SubMapping class]];
[subMapping setForceCollectionMapping:YES];
[subMapping addAttributeMappingFromKeyOfRepresentationToAttribute:#"object"];
[subMapping addAttributeMappingsFromDictionary:#{
#"(object).value" : #"value",
#"(object).unit" : #"unit"
}];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"ddata" toKeyPath:#"ddata" withMapping:subMapping]];
Can anyone tell me what I need to change in order to get the desired result? Thanks in advance. (I've been struggling with this issue for days)
Check NSSet manual
You need to use NSDictionary instead of NSSet.
Related
I'm experiencing Restkit, using the version 0.25.0. I followed exactly what the documentation says for the relationship mapping, but for some reasons, I have an empty mapping result !
But when I remove the relationship object (data), I have a mapping result !!! But of course, the mapping result doesn't contain the data I need, the one I added as relationship.
I followed the example they have in this link :
https://github.com/RestKit/RestKit/wiki/Object-mapping#relationships
When I print the JSON with the debugger, here's the output :
{
"status": "success",
"data": {
"id": 11,
"provider": "email",
"uid": "riri#gmail.com",
"name": null,
"nickname": null,
"image": null,
"email": "riri#gmail.com",
"country": "United States",
"city": "Milan, Metropolitan City of Milan, Italy",
"gender": "m",
"birthday": "2015-06-25"
}
}
Here's the code how I make the request :
RKObjectManager *manager = [RKObjectManager sharedManager];
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
RKObjectMapping *jsonResponseMapping = [JSONResponse mappingObject];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:jsonResponseMapping
method:RKRequestMethodAny
pathPattern:#"/auth/sign_in"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[manager addResponseDescriptor:responseDescriptor];
NSDictionary *parameters = #{
#"email": user.email,
#"password": user.password
};
[manager postObject:user path:#"/auth/sign_in" parameters:parameters success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSDictionary *headerFields = operation.HTTPRequestOperation.response.allHeaderFields;
[self updateUserInfoForResponse:[mappingResult firstObject] headerFields:headerFields];
if (successBlock) {
successBlock([mappingResult firstObject]);
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
if (failureBlock) {
failureBlock(error.userInfo[RKObjectMapperErrorObjectsKey][0], error);
}
}];
.m of JSONResponse class:
+ (RKObjectMapping *)mappingObject {
RKObjectMapping *jsonResponseMapping = [RKObjectMapping mappingForClass:[JSONResponse class]];
[jsonResponseMapping addAttributeMappingsFromDictionary:#{
#"status": #"status",
#"errors": #"errors",
}];
RKRelationshipMapping *userRelationShip = [RKRelationshipMapping relationshipMappingFromKeyPath:#"data" toKeyPath:#"data" withMapping:[User mappingObject]];
[jsonResponseMapping addPropertyMapping:userRelationShip];
return jsonResponseMapping;
}
.h Of JSONResponse class :
#import <RestKit/Restkit.h>
#import <Foundation/Foundation.h>
#import "User.h"
#interface JSONResponse : NSObject
#property (nonatomic, copy) NSString *status;
#property (nonatomic) User *data;
#property (nonatomic, copy) NSDictionary *errors;
/**
#function mappingObject
#return RKObjectMapping mapping for the json response
*/
+ (RKObjectMapping *)mappingObject;
#end
.m of User class
#import "User.h"
#implementation User
+ (RKObjectMapping *)mappingObject {
RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[User class]];
[userMapping addAttributeMappingsFromDictionary:#{
#"email": #"email",
#"password": #"password",
#"gender": #"gender",
#"birthday": #"dateOfBirth",
#"city": #"city",
#"country": #"country"
}];
return userMapping;
}
#end
.h of User class
#class RKObjectMapping;
#interface User : NSObject
#property (nonatomic, copy) NSString *email;
#property (nonatomic, copy) NSString *password;
#property (nonatomic, copy) NSString *gender;
#property (nonatomic, copy) NSString *dateOfBirth;
#property (nonatomic, copy) NSString *city;
#property (nonatomic, copy) NSString *country;
/**
#function mappingObject
#return RKObjectMapping mapping object for user
*/
+ (RKObjectMapping *)mappingObject;
#end
Is there anything wrong in my models objects ? The relationship is set properly right ? I do have the data property in the JSONResponse, and the JSON contains correctly the keyPath data.
So I'm pretty confused why I have results when I remove my relationship, and why the mapping result is empty when I have the relationship. It's even doesn't go in the failureCallback, the operation is successful, the result is empty.
Any ideas ??
EDIT :
Here's the logs :
2015-09-15 07:27:50.649 testRestkit[53698:3448725] D restkit.object_mapping:RKPropertyInspector.m:154 Cached property inspection for Class 'JSONResponse': {
data = "<RKPropertyInspectorPropertyInfo: 0x7facf2c5fa00>";
status = "<RKPropertyInspectorPropertyInfo: 0x7facf2c5f7d0>";
}
2015-09-15 07:27:50.650 testRestkit[53698:3448725] D restkit.object_mapping:RKPropertyInspector.m:154 Cached property inspection for Class 'User': {
email = "<RKPropertyInspectorPropertyInfo: 0x7facf2c60680>";
}
2015-09-15 07:27:50.820 testRestkit[53698:3448725] I restkit.network:RKObjectRequestOperation.m:150 POST 'http://sandrotchikovani.com/test.php'
2015-09-15 07:27:51.236 testRestkit[53698:3448938] D restkit.object_mapping:RKMapperOperation.m:407 Executing mapping operation for representation: {
data = {
email = "lol#gmail.com";
};
status = success;
}
and targetObject: <User: 0x7facf2c05820>
2015-09-15 07:27:51.237 testRestkit[53698:3448938] T restkit.object_mapping:RKMapperOperation.m:350 Examining keyPath '<null>' for mappable content...
2015-09-15 07:27:51.237 testRestkit[53698:3448938] D restkit.object_mapping:RKMapperOperation.m:330 Found mappable data at keyPath '<null>': {
data = {
email = "lol#gmail.com";
};
status = success;
}
2015-09-15 07:27:51.237 testRestkit[53698:3448938] D restkit.object_mapping:RKMapperOperation.m:433 Finished performing object mapping. Results: {
}
Isn't weird that in the log, it says and targetObject: <User: 0x7facf2c05820> ? When I remove the relationship, there is a mapping result and the targetObject, displays "null".
You are calling postObject:..., and when you do that RestKit will map back to the original object. In this case that's a user and that's why you're seeing the log and targetObject: <User: 0x7facf2c05820>.
The easiest thing for you to do is to setup your JSONResponse so that you post it and receive the response into it. It already has the required user so a simple change to the request descriptor to pull out the user fields should be enough.
Alternatively there are a bunch of other questions about mapping to a different object after posting.
How can i map this json
{
"json": [{
"json_department": [{
"department": {
"id": 1,
"inst_id": 1,
"dept_name": "Department",
"description": "test"
},
"needDelete": true
}],
"json_subjects": [{
"subjects": [{
"id": 1,
"department_id": 1,
"subject_name": "Sub 1"
}, {
"id": 2,
"department_id": 1,
"subject_name": "Sub 2"
}],
"needDelete": true
}]
}]
}
#interface class_department : NSObject
#property(nonatomic, assign) NSInteger dept_id;
#property(nonatomic, assign) NSInteger inst_id;
#property(nonatomic, strong) NSString *dept_name;
#property(nonatomic, strong) NSString *description_;
#end
_
#interface class_department_list : NSObject
#property(nonatomic, strong) class_department *department;
#property(nonatomic, assign) BOOL needDelete;
#end
-
#interface sync_json : NSObject
#property(nonatomic, strong) NSMutableArray *json_department;
#property(nonatomic, strong) NSMutableArray *json_subjects;
#end
-
-(RKResponseDescriptor *)getResponseDescriptor
{
RKObjectMapping *class_department_mapping = [RKObjectMapping mappingForClass:[class_department class]];
[class_department_mapping addAttributeMappingsFromDictionary:#{
#"id":#"dept_id",
#"inst_id":#"inst_id",
#"dept_name":#"dept_name"
#"description":#"description_",
}];
RKObjectMapping *class_department_list_mapping = [RKObjectMapping mappingForClass:[class_department_list class]];
[class_department_list_mapping addAttributeMappingsFromDictionary:#{
#"needDelete":#"needDelete"
}];
[class_department_list_mapping addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:#"json_department.department"
toKeyPath:#"department"
withMapping:class_department_mapping]];
RKObjectMapping *json_mapping = [RKObjectMapping mappingForClass:[sync_json class]];
[json_mapping addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:#"json_department"
toKeyPath:#"json_department"
withMapping:class_department_list_mapping]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:json_mapping
method:RKRequestMethodGET
pathPattern:nil
keyPath:#"json"
statusCodes:statusCodes];
return responseDescriptor;
}
OKay this is code i'm using for mapping the json. i got the result for 'needDelete' but mapping to class_department is not happen. Please give me a way to done this.
Thank you.
Shinurag KR
Sorry, but try to forget this ugly implementation. Mantle do everythig pretty easy for you. Project: https://github.com/Mantle/Mantle Example: http://www.objc.at/mantle
I'm trying to send multiple objects as an array to a Server with RestKit. Unfortunately I'm not able to do so.
Following my pretty simple objects as well as the mapping for RestKit:
Example Objects
#interface MyExampleObject : NSObject
#property NSString *key;
#property NSString *value;
#end
Array-Object holding multiple of MyExampleObject
#interface MyArray : NSObject
#property NSArray *array;
#end
Mapping
RKObjectMapping *mappingObject = [RKObjectMapping mappingForClass:[MyExampleObject class]];
[mappingObject addAttributeMappingsFromDictionary:#{
#"key" : #"key",
#"value" : #"value"
}];
RKObjectMapping *mappingArray = [RKObjectMapping mappingForClass:[MyArray class]];
[mappingArray addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"dummy" toKeyPath:#"array" mappingObject]];
If I do it this way I’ll get the following result:
{
"dummy" : [
{
"key" : "MyKey1",
"value" : "MyValue1"
},
{
"key" : "MyKey2",
"value" : "MyValue2"
}
]
}
But I want only the array without a „key“. Like this:
[
{
"key" : "MyKey1",
"value" : "MyValue1"
},
{
"key" : "MyKey2",
"value" : "MyValue2"
}
]
It seemed obvious for me to change the relationshipMappingFromKeyPath to nil. But this didn't worked (got a setObjectForKey: key cannot be nil error).
What do I have to do to send multiple MyExampleObjects to my Server as a JSON-Array?
Solution:
As Wain suggested I've removed my "Top-Mapping". Following the final mapping:
RKObjectMapping *mappingObject = [RKObjectMapping mappingForClass:[MyExampleObject class]];
[mappingObject addAttributeMappingsFromDictionary:#{
#"key" : #"key",
#"value" : #"value"
}];
And when I post the stuff to my Server I just do something like this:
NSArray *array = [NSArray arrayWithObjects:myExampleObject1, myExampleObject2, nil];
[[RKObjectManager sharedManager] postObject:array path:#"/myPath/" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
...
}
Just get rid of the MyArray object and the associated mapping and directly pass the NSArray of MyExampleObjects to the post method. RestKit will understand that it's an array of objects to map and do the right thing.
I had a JSON response of this type:
{
"d": { "id": "1", "user": "test"}
}
which I was parsing with Restkit with the following code:
#interface ODataUser : NSObject<ODataObject>
#property (nonatomic, copy) NSString * id;
#property (nonatomic, copy) NSString * user;
-(NSString*)getId;
-(NSString*)getUser;
#end
RKObjectMapping *map = [RKObjectMapping mappingForClass:[ODataUser
class]]; [mapping addAttributeMappingsFromDictionary: #{ #"id" :
#"id", #"user" : #"user" } ];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:map method:RKRequestMethodGET pathPattern:nil keyPath:#"d" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
However, now my response has changed to something like this:
{
"d": { "results": [ {"id": "1", "user": "test"} ] }
}
How can I reflect those changes on the response on my code?
Change your response descriptor to use:
keyPath:#"d.results"
as this will navigate into the d dictionary to get the results array and process all of the dictionaries it contains.
I Read From Google Places API
{
"html_attributions" : [
"Listings by \u003ca href=\"http://www.yellowpages.com.au/\"\u003eYellow Pages\u003c/a\u003e"
],
"results" : [
{
"geometry" : {
"location" : {
"lat" : -33.870540,
"lng" : 151.1988150
}
},
"icon" : "http://maps.gstatic.com/mapfiles/place_api/icons/cafe-71.png",
"id" : "c71365287e7606bd21a3311d21fda087830b7813",
"name" : "Pancakes on the Rocks",
"opening_hours" : {
"open_now" : true
},
"photos" : [
{
"height" : 1224,
"html_attributions" : [
"\u003ca href=\"https://plus.google.com/105663944571530352563\"\u003eJoshua Gilmore\u003c/a\u003e"
],
"photo_reference" : "CnRoAAAADF1JoE-joT2BSN4NEYn2luUF2kdIRjflFvETx0SbCnPyRp0TZz8_x7OlHCpAz2rrNXtQZyp5wd-JEjZh2FSpkM2bDGs_DqmktsClrnYkkirkCOHlnBHxedJf_Etv0DV8y9vnIbFnLJ9995Fk2u98SBIQxjojXwmV45p-9b4SurLQhxoUtErGJpwFe-k0hfgVGapK1FYjnWw",
"width" : 1632
}
],
"price_level" : 2,
"rating" : 3.90,
"reference" : "CoQBcgAAAFakUaktwUsNCr--KIaYu_hS9cbO8uMAwNE2W7xSMEZimIjc6EhMStq2LpVteXf6jy4UqeHGJh0QhDSpKMGK065jlnha2F6bG1zoLDRHtYTqV3PIOMMa8KsjJgmLUU-7GDojLvb6MHVctzMbMeTGtAOq_mm5lS_oymzDtJJsehSkEhCZ-KMMyl3qmYNHkCJ919FRGhSlbP1fVPQ_mLamjx9ELIBulb4ACg",
"types" : [ "cafe", "restaurant", "food", "establishment" ],
"vicinity" : "Harbourside Shopping Centre,Darling Harbour/227 & 229-230 Darling Drive, Sydney"
},
And i have Classes As Flow
Place Class:
#interface Place : NSObject
#property (nonatomic,strong) Geometry * geometry;
#property (nonatomic,strong) NSString * icon;
#property (nonatomic,strong) NSString * placeID;
#property (nonatomic,strong) NSString * name;
#property (nonatomic,strong) OpeningHours * opening_hours;
#property (nonatomic,strong) NSString * price_level;
#property (nonatomic,strong) NSString * rating;
#property (nonatomic,strong) NSString * vicinity;
#property (nonatomic,strong) NSSet *photos;
#property (nonatomic,strong) NSString *reference;
#end
And Photos Class:
#interface Photos : NSObject
#property (nonatomic,strong) NSNumber *height;
#property (nonatomic,strong) NSString *html_attributions;
#property (nonatomic,strong) NSString *photo_reference;
#property (nonatomic,strong) NSNumber *width;
#end
and i map With Follwoing:
RKObjectMapping *placeMapping = [RKObjectMapping mappingForClass:[Place class]];
[placeMapping addAttributeMappingsFromDictionary:#{
#"icon" : #"icon",
#"id" : #"placeID",
#"name" : #"name",
#"reference" : #"reference",
#"price_level" : #"price_level",
#"rating" : #"rating",
#"vicinity" : #"vicinity",
}];
// Create our new Author mapping
RKObjectMapping* geomtryMapping = [RKObjectMapping mappingForClass:[Geometry class]];
RKObjectMapping* locationMapping = [RKObjectMapping mappingForClass:[Location class]];
[locationMapping addAttributeMappingsFromArray:#[ #"lat", #"lng" ]];
[geomtryMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"location"
toKeyPath:#"location"
withMapping:locationMapping]];
[placeMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"geometry"
toKeyPath:#"geometry"
withMapping:geomtryMapping]];
RKObjectMapping* openingHoursMapping = [RKObjectMapping mappingForClass:[OpeningHours class]];
[openingHoursMapping addAttributeMappingsFromArray:#[#"open_now"]];
[placeMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"opening_hours" toKeyPath:#"opening_hours" withMapping:openingHoursMapping]];
RKObjectMapping* photosMapping = [RKObjectMapping mappingForClass:[Photos class]];
[photosMapping addAttributeMappingsFromArray:#[#"height",#"photo_reference",#"html_attributions",#"width"]];
[photosMapping setForceCollectionMapping:YES];
[placeMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"photos"
toKeyPath:#"photos"
withMapping:photosMapping]];
RKResponseDescriptor * responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:placeMapping
pathPattern:nil
keyPath:#""
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];
first Question
I Photos Alawys have value Nil.
Second Question How I get "html_attributions" in the beginning of json.
keyPaths is the bit you're missing. When you say Photos is always nil, I guess you don't really get any meaningful data? To get the places you need to specify the keyPath of #"results" on your responseDescriptor.
In a similar way, you can get the html_attributions by using it as the keyPath on another set of mappings and response descriptor.