Below is the JSON response that I get back:
{
"notificationId": 121,
"activities": [
143,
149]
}
Below is the mapping:
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[NSMutableDictionary class]];
[mapping addAttributeMappingsFromDictionary:#{#"notificationId" : #"notificationId",
#"activities": #"activities"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping
method:RKRequestMethodGET
pathPattern:nil
keyPath:#""
statusCodes:statusCodeSet];
[self.objectManager postObject:invitation path:#"/notifications" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSString *notificationId1 = [mappingResult.dictionary valueForKey:#"notificationId"];
NSArray *activitesArray1 = [mappingResult.dictionary valueForKey:#"activities"];
NSString *notificationId2 = [mappingResult.dictionary objectForKey:#"notificationId"];
NSArray *activitesArray2 = [mappingResult.dictionary objectForKey:#"activities"];
NSLog(#"notificaiton ID %#", notificationId1);
NSLog(#"Activites %#", activitesArray1);
NSLog(#"notification ID %#", notificationId2);
NSLog(#"Activites %#", activitesArray2);
NSLog(#"Activites Array %#", activitesArray);
NSLog(#"mappingResult Dictionary %#", mappingResult.dictionary);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"Failusre");
}];
}
Log:
2014-04-21 19:17:51.273 App[57446:4403] I restkit.network:RKObjectRequestOperation.m:250 POST 'http://www.domain.com/notifications' (200 OK / 1 objects) [request=0.2371s mapping=0.0035s total=0.2446s]
2014-04-21 19:17:51.274 App[57446:60b] notification ID (null)
2014-04-21 19:17:51.274 App[57446:60b] Activites (null)
2014-04-21 19:17:51.274 App[57446:60b] notification ID (null)
2014-04-21 19:17:51.274 App[57446:60b] Activites (null)
2014-04-21 19:17:51.274 App[57446:60b] Activites Array (
)
2014-04-21 19:17:51.275 App[57446:60b] mappingResult Dictionary {
"" = {
activities = (
143,
149
);
notificationId = 121;
};
}
Why are all the values Null? How can I get the values of notificationId back as an NSString and activitiesin an array ? Can this be done without creating a mapping class?
Because your response descriptor is wrong. It should be:
[RKResponseDescriptor responseDescriptorWithMapping:mapping
method:RKRequestMethodPOST
pathPattern:#"/notifications"
keyPath:nil
statusCodes:statusCodeSet];
so that it matches the request you're sending (a POST, not a GET is the main issue).
For some unknow reason, it looks like, there is a wrapper object in the dictionary, that has key value #"" so first extract that and then everything else. Activities itself do look like array, so simply:
NSArray *activities = [[mappingResult.dictionary objectForKey:#""] objectForKey:#"activities"];
However that notification looks tricky, because it probably is a number. So if it is a consistent type, use:
NSNumber *notificationID = [[mappingResult.dictionary objectForKey:#""] objectForKey:#"notificationId"];
NSSring *notificationIDString = [notificationID stringValue];
Related
I have route
[RKRoute routeWithClass:[BBComment class] pathPattern:#"/comments" method:RKRequestMethodPOST]
And response descriptor
[RKResponseDescriptor responseDescriptorWithMapping:[BBComment apiMapping] method:RKRequestMethodPOST pathPattern:#"/comments" keyPath:nil statusCodes:successCodes]
Here route when post object
<RKClassRoute: 0x7fe2da8d65e0 objectClass=BBComment method=(POST) pathPattern=comment>
Printing description of routingMetadata:
{
query = {
parameters = {
"post_id" = 3205;
text = ds;
};
};
routing = {
parameters = {
};
route = "<RKClassRoute: 0x7fe2da8d65e0 objectClass=BBComment method=(POST) pathPattern=comment>";
};
}
Before post a new Comment i create temp object
BBComment *wComm = [BBComment MR_createEntity];
and then
[[RKObjectManager sharedManager] postObject:wComm path:nil parameters:sendCommentData success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
BBLog(#"ret:%#", wComm);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
}];
Firstly:
In RestKit operation create
NSSet *temporaryObjects = [[managedObjectContext insertedObjects] filteredSetUsingPredicate:temporaryObjectsPredicate];
it's empty
But i think it's not a key.
After response from server i got two different objects wComm and from responseResult
Why? I think what RestKit update given object instead creating a new one?
Here objects before and after POST
(lldb) po [wComm objectID]
0xd00000000050001c <x-coredata://C721341D-CAA2-4240-809B-D3F2D45032B5/BBComment/p20>
(lldb) po [mappingResult.firstObject objectID]
0xd00000000054001c <x-coredata://C721341D-CAA2-4240-809B-D3F2D45032B5/BBComment/p21>
I try save object before post (like a RestKit do if object is temp) - nothing changes.
I think maybe different contexts? But no
(lldb) po wComm.managedObjectContext
<NSManagedObjectContext: 0x7fa442c42080>
(lldb) po [mappingResult.firstObject managedObjectContext]
<NSManagedObjectContext: 0x7fa442c42080>
UPDATE
Not, i get object, not an array like here
What is the relationship between the post object, in the RestKit postObject method, and the RKMappingResult it returns?
I found why it's not work. Because targetObject not set in operation
Problem in this function
if (RKDoesArrayOfResponseDescriptorsContainMappingForClass(self.responseDescriptors, [object class])) operation.targetObject = object;
It's work by ALL descriptors, not only for matching responseDescriptors, but ALL WTF?
And it's return NO for object.
Mapping for this object is RKDynamicMapping.
PROBLEM FOUND
Here problem: not use setObjectMappingForRepresentationBlock
Because u will get
po [mapping objectMappings]
<__NSArray0 0x7fcdd8d0ad30>(
)
And function of RKMappingGraphVisitor will not work.
SOLUTION 1
Get RKOperation and set manually targetObject. But i think it's not correct.
BETTER SOLUTION
Use something like
+ (RKDynamicMapping *)apiMapping {
RKDynamicMapping *mapping = [RKDynamicMapping new];
[mapping addMatcher:[RKObjectMappingMatcher matcherWithKeyPath:#"type" expectedValue:BBMessageType.plain objectMapping:[self plainTypeMapping]]];
return mapping;
}
Hi I'm trying to post NSManagedObject to the server using Rest Kit. Could somebody take a look and tell me what I'm doing wrong ?
This is my json structure for post request which I tested by using RubyMine REST client and it posted object properly:
{
"name":"test name",
"mobile":"22334455",
"dob":"1989-12-12",
"medications":"test",
"medical_conditions":"",
"watch":
{
"phonewatchno":"123789",
"latitude":-33.99,
"longitude":151.11,
"gmaps":null,
"battery_life":null,
"last_update_time":null,
"location":"",
"short_imei":null,
"rssi":null,
"charging_status":null,
"voltage":null,
"network":null,
"altitude":null,
"ip_addr":null,
"button_press_time":null,
"last_keep_alive":null
}
}
My post method looks like the following one :
id params = #{#"name": #"Tinder",
#"mobile":#"20934920",
#"dob":#"1989-12-12",
#"medications":#"pills",
#"medical_conditions":#"lkas",
#"watch":
#{
#"phonewatchno":#"239847239",
#"latitude":#"-33.99",
#"longitude":#"151.11",
#"gmaps":#"",
#"battery_life":#"",
#"last_update_time":#"",
#"location":#"",
#"short_imei":#"",
#"rssi":#"",
#"charging_status":#"",
#"voltage":#"",
#"network":#"",
#"altitude":#"",
#"ip_addr":#"",
#"button_press_time":#"",
#"last_keep_alive":#""
}
};
RKResponseDescriptor *responseDescr= [RKResponseDescriptor responseDescriptorWithMapping:[MappingProvider myMapping] method:RKRequestMethodPOST pathPattern:#"/myPath.json" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager]addResponseDescriptor:responseDescr];
[[RKObjectManager sharedManager]setRequestSerializationMIMEType:RKMIMETypeJSON];
[[[RKObjectManager sharedManager]HTTPClient]postPath:#"/myPath.json" parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Mapped object %#",responseObject);
[self dismissViewControllerAnimated:YES completion:nil];
} failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"An error occuered: %#",error);
}];
}
Thanks in advance
EDIT 1:
NSEntityDescription *watchEntityDesc = [NSEntityDescription entityForName:#"Watches" inManagedObjectContext:[[RKObjectManager sharedManager]managedObjectStore].mainQueueManagedObjectContext];
Watches *watch = [[Watches alloc]initWithEntity:watchEntityDesc insertIntoManagedObjectContext:[[RKObjectManager sharedManager]managedObjectStore].mainQueueManagedObjectContext];
watch.phonewatchno = [NSNumber numberWithInt:124512];
watch.latitude = [NSNumber numberWithDouble:-33.99];
watch.longitude = [NSNumber numberWithDouble:151.11];
watch.location = #"test location";
watch.gmaps = [NSNumber numberWithInt:12];
watch.battery_life = [NSNumber numberWithInt:78];
watch.last_update_time = [NSDate date];
watch.last_keep_alive = [NSDate date];
watch.short_imei = [NSNumber numberWithInt:1233];
watch.rssi = [NSNumber numberWithInt:2];
watch.charging_status = [NSNumber numberWithInt:1];
watch.voltage = [NSNumber numberWithInt:200];
watch.network = #"WIFI";
watch.altitude = [NSNumber numberWithInt:1];
watch.ip_addr = #"196.12.12.04";
watch.button_press_time = [NSNumber numberWithInt:4];
NSEntityDescription *wearersEntityDesc = [NSEntityDescription entityForName:#"Wearers" inManagedObjectContext:[[RKObjectManager sharedManager]managedObjectStore].mainQueueManagedObjectContext];
Wearers *wearer = [[Wearers alloc]initWithEntity:wearersEntityDesc insertIntoManagedObjectContext:[[RKObjectManager sharedManager]managedObjectStore].mainQueueManagedObjectContext];
wearer.name =#"test";
wearer.mobile = #"109283190";
wearer.medical_conditions = #"test";
wearer.medications = #"test";
wearer.dob = [NSDate date];
wearer.watches = [NSSet setWithObject:watch];
RKEntityMapping *watchesMapping = [RKEntityMapping mappingForEntityForName:#"Watches" inManagedObjectStore:[[EdisseDateModel sharedDataModel]objectStore]];
[watchesMapping addAttributeMappingsFromDictionary:#{
#"id": #"watch_id",
#"altitude":#"altitude",
#"battery_life":#"battery_life",
#"button_press_time":#"button_press_time",
#"charging_status":#"charging_status",
#"gmaps":#"gmaps",
#"ip_addr":#"ip_addr",
#"last_keep_alive":#"last_keep_alive",
#"last_update_time":#"last_update_time",
#"latitude":#"latitude",
#"longitude":#"longitude",
#"location":#"location",
#"network":#"network",
#"phonewatchno":#"phonewatchno",
#"rssi":#"rssi",
#"short_imei":#"short_imei",
#"updated_at":#"updated_at",
#"voltage":#"voltage",
#"wearer_id":#"wearer_id",
#"updated_at":#"updated_at",
}
];
[watchesMapping addConnectionForRelationship:#"wearer" connectedBy:#{
#"wearer_id":#"wearer_id"
}];
[watchesMapping setIdentificationAttributes:#[#"watch_id"]];
RKResponseDescriptor *responseDescr = [RKResponseDescriptor responseDescriptorWithMapping:watchesMapping method:RKRequestMethodPOST pathPattern:#"/watches.json" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager]addResponseDescriptor:responseDescr];
RKEntityMapping *wearersMapping = [RKEntityMapping mappingForEntityForName:#"Wearers" inManagedObjectStore:[[EdisseDateModel sharedDataModel] objectStore]];
[wearersMapping addAttributeMappingsFromDictionary:#{
#"id":#"wearer_id",
#"at_risk": #"at_risk",
#"created_at": #"created_at",
#"dob": #"dob",
#"geo_radius": #"geo_radius",
#"medical_conditions":#"medical_conditions",
#"medications":#"medications",
#"mobile":#"mobile",
#"name":#"name",
#"status":#"status",
#"updated_at":#"updated_at",
#"wearer_photo_content_type":#"wearer_photo_content_type",
#"wearer_photo_file_size":#"wearer_photo_file_size",
#"wearer_photo_file_name":#"wearer_photo_file_name",
}
];
wearersMapping.identificationAttributes = #[#"wearer_id"];
[wearersMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"watch" toKeyPath:#"watches" withMapping:watchesMapping]];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:wearersMapping method:RKRequestMethodPOST pathPattern:#"/wearers.json" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[wearersMapping inverseMapping] objectClass:[Wearers class] rootKeyPath:nil method:RKRequestMethodPOST ];
[[RKObjectManager sharedManager]addResponseDescriptor:responseDescriptor];
[[RKObjectManager sharedManager]addRequestDescriptor:requestDescriptor];
[[RKObjectManager sharedManager]setRequestSerializationMIMEType:RKMIMETypeJSON];
[[RKObjectManager sharedManager]setAcceptHeaderWithMIMEType:#"application/json"];
[[RKObjectManager sharedManager]postObject:wearer path:#"/wearers.json" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
{
NSLog(#"Response : %#",mappingResult.array);
}
failure:^(RKObjectRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %#",error.userInfo.description);
}];
Now I'm getting error from failure block in my Xcode console like below :
Error: {
AFNetworkingOperationFailingURLRequestErrorKey = "<NSMutableURLRequest: 0x178210760> { URL: https://www.test.com/wearers.json }";
AFNetworkingOperationFailingURLResponseErrorKey = "<NSHTTPURLResponse: 0x170421be0> { URL: https://www.test.com/wearers.json } { status code: 500, headers {\n Connection = \"keep-alive\";\n \"Content-Length\" = 48;\n \"Content-Type\" = \"application/json; charset=utf-8\";\n Date = \"Fri, 06 Jun 2014 03:43:59 GMT\";\n Server = \"nginx/1.6.0 + Phusion Passenger 4.0.42\";\n Status = \"500 Internal Server Error\";\n \"X-Powered-By\" = \"Phusion Passenger 4.0.42\";\n \"X-Request-Id\" = \"6ce273e7-4130-47c3-91de-8020db49426a\";\n \"X-Runtime\" = \"0.011948\";\n} }";
NSErrorFailingURLKey = "https://www.test.com/wearers.json";
NSLocalizedDescription = "Expected status code in (200-299), got 500";
NSLocalizedRecoverySuggestion = "{\"status\":\"500\",\"error\":\"Internal Server Error\"}";
You need to create a request descriptor against NSDictionary and then not use the HTTPClient to action the post, just use the object manager (because the client knows nothing about request or response descriptors).
Following your edit your server is throwing an error - check the server log. Your code now looks ok for sending wearers with nested watches and receiving watches and connecting them by foreign key mapping. You need to check exactly what is sent with Charles against what the server is expecting.
So, i m sending a POST request for the first time. I m Mapping classes and as I thought and read from the Documentation that it would work in this way:
Init RK:
- (void)initRK{
if(!manager){
manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:BASE_CONTEXT_URL]];
}
if (!reqMapping) {
reqMapping = [RKObjectMapping requestMapping];
}
}
POST Method:
// Configure a request mapping for our Article class. We want to send back title, body, and publicationDate
RKObjectMapping* deviceRequestMapping = [RKObjectMapping mappingForClass:[DeviceDTO class]];
[deviceRequestMapping addAttributeMappingsFromArray:#[ #"model", #"name", #"systemName", #"systemVersion", #"devToken" ]];
RKObjectMapping* msRequestMapping = [RKObjectMapping mappingForClass:[MemberShipDTO class]];
[msRequestMapping addAttributeMappingsFromArray:#[ #"validSince", #"validTill" ]];
RKObjectMapping* countryRequestMapping = [RKObjectMapping mappingForClass:[CountryDTO class]];
[countryRequestMapping addAttributeMappingsFromArray:#[ #"idNumberDTO", #"iso2DTO", #"short_nameDTO", #"calling_codeDTO" ]];
RKObjectMapping* userRequestMapping = [RKObjectMapping requestMapping];
[userRequestMapping addAttributeMappingsFromArray:#[ #"displayName", #"phoneNumber", #"status", #"userID" ]];
[userRequestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:#"device" withMapping:deviceRequestMapping]];
[userRequestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:#"memberShip" withMapping:msRequestMapping]];
[userRequestMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:nil toKeyPath:#"country" withMapping:countryRequestMapping]];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:userRequestMapping objectClass:[User class] rootKeyPath:#"user"];
//Create Objects
UserDTO *user = [[UserDTO alloc]init];
user.displayName = userDTO.displayName;
user.phoneNumber = userDTO.phoneNumber;
user.status = userDTO.status;
user.userID = userDTO.userID;
user.country = userDTO.country;
DeviceDTO *device = [[DeviceDTO alloc]init];
device.name = devDTO.name;
device.systemName = devDTO.systemName;
device.systemVersion = devDTO.systemVersion;
device.model = devDTO.model;
device.devToken = [[NSUserDefaults standardUserDefaults]objectForKey:PUSHTOKEN_USER_DEFAULTS_KEY];
user.deviceInfo = device;
MemberShipDTO *ms = [[MemberShipDTO alloc]init];
ms.validSince = [NSDate date];
ms.validTill = [[UtilitieHandler new] getDateByAdd:+1 :0 :0 :0];
user.memberShipDetails = ms;
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:#"application/json"];
[[RKObjectManager sharedManager] setRequestSerializationMIMEType:RKMIMETypeJSON];
[[RKObjectManager sharedManager] setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[[RKObjectManager sharedManager] addRequestDescriptor:requestDescriptor];
[[RKObjectManager sharedManager] postObject:user path:#"user/integrate" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult){
RKLogInfo(#"Load collection of Articles: %#", mappingResult.array);
}failure:^(RKObjectRequestOperation *operation, NSError *error) {
RKLogError(#"Operation failed with error: %#", error);
}];
So I tried different things and after i used wireshark to capture the request it returns that theres no content send. That means the mapping is not working correct. I tried a lot and nothing helped. Any advice would be great!
Here the captured packet:
POST /WAZZUUPWS/rest/service/user/integrate HTTP/1.1
Host: 192.168.2.115:8080
Accept-Encoding: gzip, deflate
Accept: application/json
Content-Length: 0
Connection: keep-alive
Accept-Language: de;q=1, en;q=0.9, fr;q=0.8, ja;q=0.7, nl;q=0.6, it;q=0.5
User-Agent: WAZZUUP!/1.0 (iPhone; iOS 6.1.4; Scale/2.00)
It might just be a typo in your question but requestDescriptor doesn't appear to be linked to the UserDTO class.
It seems like you do not have an understanding of Core Data objects yet. Objects that are persisted using Core Data are subclasses of NSManagedObject and have to be created differently. Read further on this link:
http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/CoreData/Articles/cdCreateMOs.html
As for the current problem, you have to use this instead:
NSEntityDescription *entity = [NSEntityDescription entityForName:#"UserDTO" inManagedObjectContext:[RKManagedObjectStore defaultStore].mainQueueManagedObjectContext];
UserDTO *user = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:nil];
However, if UserDTO is a subclass of NSObject, that would need to change to NSManagedObject.
My workflow is something like this - create Core Data model and use mogenerator to automatically generate the NSManagedObject class definitions. Read more about it here:http://raptureinvenice.com/getting-started-with-mogenerator/
I'm struggling to even get basic stuff working in restkit. I am an experienced developer too which makes it even more frustrating.
I have successfully have it posting a json object to my service and via debugging through the RestKit source I have verified that the desired json has been returned. It returns to the success block but with nothing except an empty object.
Here is my code that sets up the mappings and launches the request.
Note: I have obscured some sensitive passwords/urls.
RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
[requestMapping addAttributeMappingsFromDictionary:#{ #"DeviceKey": #"DeviceKey", #"DeviceName": #"DeviceName", #"Password": #"Password", #"Username": #"Username"}];
RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping
objectClass:[LoginRequest class]
rootKeyPath:nil];
RKObjectMapping *responseMapping = [RKObjectMapping mappingForClass:[LoginResponse class]];
responseMapping.forceCollectionMapping = YES;
[responseMapping addAttributeMappingsFromDictionary:#{#"TotalBalance":#"TotalBalance",#"FirstName":#"FirstName"}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:responseMapping
pathPattern:#"Login"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectManager *manager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:#"http://api.test.com/account/"]];
[manager addRequestDescriptor:requestDescriptor];
[manager addResponseDescriptor:responseDescriptor];
manager.requestSerializationMIMEType = RKMIMETypeJSON;
LoginRequest *request = [[LoginRequest alloc] init];
request.DeviceKey = #"xxxxxxx";
request.DeviceName = #"iPhone";
request.Username = #"mike";
request.Password = #"******";
[manager postObject:request path:#"Login" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *result) {
NSArray * array = [result array];
NSDictionary * dictionary = [result dictionary];
NSObject * obj = [result firstObject];
NSLog(#"We object mapped the response with the following result: %#", result);
// It ends up in the success callback but all of these are EMPTY :(
} failure:^(RKObjectRequestOperation *operation, NSError *err){
NSLog(#"We had a problemo");
}];
LogonResponse.h (the .m simply synthisizes them properties)
#import <Foundation/Foundation.h>
#interface LoginResponse : NSObject
#property(nonatomic,assign) double TotalBalance;
#property(nonatomic,retain) NSString * FirstName;
#end
The JSON:
{
"TotalBalance":22.34,
"FirstName":"Mike"
........ other stuff but this shouldn't matter
}
The console is showing:
2013-06-26 14:03:07.173 Tests.com[1666:907] I restkit.support:RKMIMETypeSerialization.m:115 JSON Serialization class 'RKNSJSONSerialization' detected: Registering for MIME Type 'application/json
2013-06-26 14:03:07.181 Tests.com[1666:3907] T restkit.network:RKHTTPRequestOperation.m:139 POST 'http://api.test.com/account/Login':
request.headers={
Accept = "application/json";
"Accept-Language" = "en-GB, en, fr, de, ja, nl, it, es, pt, pt-PT, da, fi, nb, sv, ko, zh-Hans, zh-Hant, ru, pl, tr, uk, ar, hr, cs, el, he, ro, sk, th, id, ms, ca, hu, vi, en-us;q=0.8";
"Content-Type" = "application/json; charset=utf-8";
"User-Agent" = "Tests.com/2.10.31_dev (iPad; iOS 6.1.3; Scale/1.00)";
}
request.body={"DeviceKey":"xxxxxxx","DeviceName":"iPhone","Password":"******","Username":"mike"}
2013-06-26 14:03:07.297 Tests.com[1666:162f] D restkit.network:RKHTTPRequestOperation.m:191 Received authentication challenge
2013-06-26 14:03:08.016 Tests.com[1666:162f] T restkit.network:RKHTTPRequestOperation.m:156 POST 'http://api.test.com/account/Login' (200):
response.headers={
"Content-Length" = 1172;
"Content-Type" = "application/json; charset=utf-8";
Date = "Wed, 26 Jun 2013 04:03:04 GMT";
Server = "Microsoft-IIS/7.5";
Vary = "Accept-Encoding";
"X-Powered-By" = "ASP.NET";
}
response.body={"CustomerReference":"50713881","FirstName":"Mike","TotalBalance":22.25,"ErrorInfo":null,"Success":true}
2013-06-26 14:03:08.021 Tests.com[1666:3b13] W restkit.object_mapping:RKMapperOperation.m:76 Adding mapping error: Cannot map a collection of objects onto a non-mutable collection. Unexpected destination object type 'LoginRequest'
(lldb)
Why is it going on about LoginRequest?? I'm so lost!!
Any help would be very much appreciated.
When you make a post request with RestKit, I believe the mapper tries to map the response to the same object type that was sent. In this case, because a LoginRequest was sent it wants to map the response to a LoginRequest object.
A solution to this might be to create a temporary LoginResponse object and post that with a dictionary containing your login request fields (username, password, etc.). That way, RestKit will be able to map the response into the temporary object that you created.
Upgrading to v0.20.3 fixed this issue.
I'm trying to use RestKit 0.20-pre3 together with RKXMLReaderSerialization and XMLReader in order to map a XML response from a WebService like this:
<ArrayOfAddressBookItem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<AddressBookItem>
<CommonName>xxxxxxxxxx</CommonName>
<OU>xxxxxx</OU>
<Name>xxxxxx</Name>
<LastName>xxxxxxxxxx</LastName>
<Service>xxxxxxxxxx</Service>
<Email>xxxxxxxxxxxx</Email>
<InternalPhoneNumber>xxxxxxxxxxx</InternalPhoneNumber>
<ExternalPhoneNumber>xxxxxxxxxxx</ExternalPhoneNumber>
<Mobile>xxxxxxxxxxx</Mobile>
<Street>xxxxxxxxxxx</Street>
<PostalCode>xxxxxxxxxxx</PostalCode>
<City>xxxxxxx</City>
<County>xxxxxxxxx</County>
<SupervisorCommonName>
xxxxxxxxxxxxx
</SupervisorCommonName>
<SupervisorLastName>xxxxxxxxxx</SupervisorLastName>
</AddressBookItem>
<AddressBookItem>
<CommonName>yyyyyyyyyyyy</CommonName>
<OU>
yyyyyyyyyyyyy
</OU>
<Name>yyyyyyyyy</Name>
<LastName>yyyyyyyy</LastName>
<Service>yyyyyyyyyy</Service>
<Email>yyyyyyyyyy</Email>
<InternalPhoneNumber>yyyyyyyyy</InternalPhoneNumber>
<ExternalPhoneNumber>yyyyyyyy</ExternalPhoneNumber>
<Street>yyyyyyyyyyy</Street>
<PostalCode>yyyyyy</PostalCode>
<City>yyyyyy</City>
<County>yyyyyyyy</County>
<SupervisorCommonName>
yyyyyyyyyyy
</SupervisorCommonName>
<SupervisorLastName>yyyyyy</SupervisorLastName>
</AddressBookItem>
<AddressBookItem>
....
</AddressBookItem>
<AddressBookItem>
</ArrayOfAddressBookItem>
In the App Delegation code:
[RKMIMETypeSerialization registerClass:[RKXMLReaderSerialization class] forMIMEType:#"application/xml"];
AFHTTPClient *httpClient = [AFHTTPClient clientWithBaseURL:[NSURL URLWithString:#"http://thehostaddress/mywebserviceurl/"]];
httpClient.parameterEncoding = AFFormURLParameterEncoding;
RKObjectManager *objManager = [[RKObjectManager alloc] initWithHTTPClient:httpClient];
[objManager setAcceptHeaderWithMIMEType:RKMIMETypeTextXML];
objManager.requestSerializationMIMEType = RKMIMETypeTextXML;
RKObjectMapping *personMapping = [RKObjectMapping mappingForClass:[PersonItem class]];
[personMapping addAttributeMappingsFromDictionary:#{#"CommonName" : #"commonName", #"OU" : #"ou", #"Name" : #"name", #"LastName" : #"lastName", #"Service" : #"service", #"Email" : #"eMail", #"InternalPhoneNumber" : #"internalPhoneNumber", #"ExternalPhoneNumber" : #"externalPhoneNumber", #"Mobile" : #"mobilePhoneNumber", #"Street" : #"street", #"PostalCode" : #"postalCode", #"City" : #"city", #"County" : #"county", #"SupervisorCommonName" : #"supervisorCommonName", #"SupervisorLastName" : #"supervisorLastName"}];
RKResponseDescriptor *peopleResponse = [RKResponseDescriptor responseDescriptorWithMapping:personMapping pathPattern:#"/mywebserviceurl/" keyPath:#"ArrayOfAddressBookItem" statusCodes:[NSIndexSet indexSetWithIndex:200]];
[objManager addResponseDescriptor:peopleResponse];
later, when I want to get the objects:
[objManager getObjectsAtPath:#"/mywebserviceurl/" parameters:nil
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(#"SUCCESS: %#", mappingResult);
_items = [[mappingResult array] mutableCopy];
}
failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(#"ERROR: %#", error);
}];
I can see that the mapper gets the correct number of the Array elements, but for each field of the object, I cannot retrieve the values:
2012-12-10 19:02:53.370 GenPeople2[14240:1703] T restkit.object_mapping:RKMappingOperation.m:341 Mapping attribute value keyPath 'CommonName' to 'commonName'
2012-12-10 19:02:53.370 GenPeople2[14240:1703] T restkit.object_mapping:RKMappingOperation.m:228 Found transformable value at keyPath 'CommonName'. Transforming from type '__NSDictionaryM' to 'NSString'
2012-12-10 19:02:53.371 GenPeople2[14240:1703] T restkit.object_mapping:RKMappingOperation.m:360 Skipped mapping of attribute value from keyPath 'CommonName to keyPath 'commonName' -- value is unchanged ((null))
and the result in my objects are null values.
I saw that the XML parser gives me back this:
2012-12-10 19:02:53.371 GenPeople2[14240:1703] D restkit.object_mapping:RKMapperOperation.m:218 Asked to map source
object {
City = {
text = thecity;
};
CommonName = {
text = thename;
};
County = {
text = thecounty;
};
and so on....
How to map correctly the values in order to permit RestKit to retrieve the values in the NSDictionary for each field ?
Thank Richard for your feedback, but it didn't work as I would like.
Really simpler: using nested keypaths in source object to map, worked as a charm:
RKObjectMapping *abItemMapping = [RKObjectMapping mappingForClass:[AddressBookItem class]];
[abItemMapping addAttributeMappingsFromDictionary:#{#"CommonName.text" : #"commonName", #"OU.text" : #"ou", #"Name.text" : #"name", #"LastName.text" : #"lastName", #"Service.text" : #"service", #"Email.text" : #"email"}];
I map the child nodes of an element as their own objects. So OU for example would be represented by a mapping and relationship of it's own:
RKObjectMapping *baseValueMapping = [RKObjectMapping mappingForClass:[CHRValue class]];
[baseValueMapping addAttributeMappingsFromDictionary:#{#"text" : #"value"}];
RKRelationshipMapping *ouRelation = [RKRelationshipMapping relationshipMappingFromKeyPath:#"OU" toKeyPath:#"ou" withMapping:baseValueMapping];
RKRelationshipMapping *nameRelation = [RKRelationshipMapping relationshipMappingFromKeyPath:#"Name" toKeyPath:#"name" withMapping:baseValueMapping];
[addressBookMapping addPropertyMapping:ouRelation];
[addressBookMapping addPropertyMapping:nameRelation];
Where CHRValue has a property named "value" which is an NSString. Note you need to use "text" to refer to the value of a node.