59572

Having problems with Restkit nested mappings

Question:

I've been trying to create a request to a login service, but i'm having problems when receiving the response, and i don't know what i'm doing wrong.

Here's my code:

<strong>AppDelagate</strong>

/* LOGIN RESPONSE */ RKObjectMapping *userMapping = [RKObjectMapping mappingForClass:[UserMapping class]]; [userMapping addAttributeMappingsFromDictionary:@{ @"_id":@"_id", @"name": @"name", @"lastname": @"lastname", @"username": @"username", @"password": @"password", @"repeatPassword": @"repeatPassword", @"age": @"age", @"gender": @"gender", @"photo": @"photo"}]; RKObjectMapping *loginResponseMapping = [RKObjectMapping mappingForClass:[LoginResponse class]]; [loginResponseMapping addAttributeMappingsFromArray:@[ @"code", @"message" ]]; [loginResponseMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"data" toKeyPath:@"data" withMapping:userMapping]]; RKResponseDescriptor *loginResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:loginResponseMapping method:RKRequestMethodPOST pathPattern:nil keyPath:nil statusCodes:[NSIndexSet indexSetWithIndex:200]]; [manager addResponseDescriptor:baseResponseDescriptor]; [manager addRequestDescriptor:loginRequestDescriptor]; [manager addResponseDescriptor:loginResponseDescriptor]; [manager addRequestDescriptor:signupRequestDescriptor]; /* SERIALIZATION TYPE */ [manager setRequestSerializationMIMEType:RKMIMETypeJSON];

<strong>LoginResponse class</strong>

@interface LoginResponse : NSObject @property (nonatomic, strong) NSNumber *code; @property (nonatomic, strong) NSString *message; @property (nonatomic, strong) UserMapping *data; @end

<strong>UserMapping class</strong>

@interface UserMapping : NSObject @property (nonatomic, strong) NSString *_id; @property (nonatomic, strong) NSString *name; @property (nonatomic, strong) NSString *lastname; @property (nonatomic, strong) NSString *age; @property (nonatomic, strong) NSString *gender; @property (nonatomic, strong) NSString *username; @property (nonatomic, strong) NSString *password; @property (nonatomic, strong) NSString *repeatPassword; @property (nonatomic, strong) NSString *photo; @end

<strong>LOG:</strong>

2014-03-07 14:56:19.439 Shoopi[8149:a0b] D restkit.object_mapping:RKMappingOperation.m:952 Starting mapping operation... 2014-03-07 14:56:19.440 Shoopi[8149:a0b] T restkit.object_mapping:RKMappingOperation.m:953 Performing mapping operation: <RKMappingOperation 0xbb711f0> for '__NSDictionaryM' object. Mapping values from object <LoginRequest: 0xbbcfb20> ((null)) to object { } with object mapping (null) 2014-03-07 14:56:19.441 Shoopi[8149:a0b] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'username' to 'username' 2014-03-07 14:56:19.442 Shoopi[8149:410b] D restkit.object_mapping:RKPropertyInspector.m:130 Cached property inspection for Class 'NSMutableDictionary': { fileHFSFlags = { isPrimitive = 1; keyValueCodingClass = NSNumber; name = fileHFSFlags; }; fileHFSResourceForkSize = { isPrimitive = 1; keyValueCodingClass = NSNumber; name = fileHFSResourceForkSize; }; } 2014-03-07 14:56:19.442 Shoopi[8149:a0b] T restkit.object_mapping:RKMappingOperation.m:572 Mapped attribute value from keyPath 'username' to 'username'. Value: test@test.cl 2014-03-07 14:56:19.443 Shoopi[8149:a0b] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'password' to 'password' 2014-03-07 14:56:19.443 Shoopi[8149:410b] D restkit.object_mapping:RKPropertyInspector.m:130 Cached property inspection for Class 'LoginRequest': { password = { isPrimitive = 0; keyValueCodingClass = NSString; name = password; }; username = { isPrimitive = 0; keyValueCodingClass = NSString; name = username; }; } 2014-03-07 14:56:19.445 Shoopi[8149:a0b] T restkit.object_mapping:RKMappingOperation.m:572 Mapped attribute value from keyPath 'password' to 'password'. Value: 1234 2014-03-07 14:56:19.446 Shoopi[8149:a0b] D restkit.object_mapping:RKMappingOperation.m:1021 Finished mapping operation successfully... 2014-03-07 14:56:19.450 Shoopi[8149:a0b] AJUA ! 2014-03-07 14:56:19.456 Shoopi[8149:a0b] T restkit.network:RKObjectRequestOperation.m:178 POST 'http://shoppi-services.herokuapp.com/public/login': request.headers={ Accept = "application/json"; "Accept-Language" = "en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5"; "Content-Type" = "application/json; charset=utf-8"; "User-Agent" = "Shoopi/1.0 (iPhone Simulator; iOS 7.0; Scale/2.00)"; } request.body={"username":"test@test.cl","password":"1234"} 2014-03-07 14:56:19.981 Shoopi[8149:410b] D restkit.object_mapping:RKMapperOperation.m:377 Executing mapping operation for representation: { code = 0; data = "{\"_id\":\"5319459fe6b6558526000001\",\"age\":\"19\",\"gender\":\"female\",\"lastname\":\"test\",\"name\":\"test\",\"password\":\"1234\",\"photo\":null,\"repeatPassword\":\"1234\",\"username\":\"test@test.cl\"}"; message = Success; } and targetObject: (null) 2014-03-07 14:56:19.982 Shoopi[8149:410b] T restkit.object_mapping:RKMapperOperation.m:320 Examining keyPath '' for mappable content... 2014-03-07 14:56:19.982 Shoopi[8149:410b] D restkit.object_mapping:RKMapperOperation.m:300 Found mappable data at keyPath '': { code = 0; data = "{\"_id\":\"5319459fe6b6558526000001\",\"age\":\"19\",\"gender\":\"female\",\"lastname\":\"test\",\"name\":\"test\",\"password\":\"1234\",\"photo\":null,\"repeatPassword\":\"1234\",\"username\":\"test@test.cl\"}"; message = Success; } 2014-03-07 14:56:19.983 Shoopi[8149:410b] D restkit.object_mapping:RKMapperOperation.m:231 Asked to map source object { code = 0; data = "{\"_id\":\"5319459fe6b6558526000001\",\"age\":\"19\",\"gender\":\"female\",\"lastname\":\"test\",\"name\":\"test\",\"password\":\"1234\",\"photo\":null,\"repeatPassword\":\"1234\",\"username\":\"test@test.cl\"}"; message = Success; } with mapping <RKObjectMapping:0x8c9e1e0 objectClass=BaseModel propertyMappings=( "<RKAttributeMapping: 0x8cadf20 code => code>", "<RKAttributeMapping: 0x8ca6920 message => message>" )> 2014-03-07 14:56:19.984 Shoopi[8149:410b] D restkit.object_mapping:RKMappingOperation.m:952 Starting mapping operation... 2014-03-07 14:56:19.984 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:953 Performing mapping operation: <RKMappingOperation 0xbb6db80> for 'BaseModel' object. Mapping values from object { code = 0; data = "{\"_id\":\"5319459fe6b6558526000001\",\"age\":\"19\",\"gender\":\"female\",\"lastname\":\"test\",\"name\":\"test\",\"password\":\"1234\",\"photo\":null,\"repeatPassword\":\"1234\",\"username\":\"test@test.cl\"}"; message = Success; } to object <BaseModel: 0xbbf2b80> with object mapping (null) 2014-03-07 14:56:19.985 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'code' to 'code' 2014-03-07 14:56:19.986 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:572 Mapped attribute value from keyPath 'code' to 'code'. Value: 0 2014-03-07 14:56:19.986 Shoopi[8149:1007] D restkit.object_mapping:RKPropertyInspector.m:130 Cached property inspection for Class 'BaseModel': { code = { isPrimitive = 0; keyValueCodingClass = NSNumber; name = code; }; message = { isPrimitive = 0; keyValueCodingClass = NSString; name = message; }; } 2014-03-07 14:56:19.986 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'message' to 'message' 2014-03-07 14:56:19.986 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:572 Mapped attribute value from keyPath 'message' to 'message'. Value: Success 2014-03-07 14:56:19.987 Shoopi[8149:410b] D restkit.object_mapping:RKMappingOperation.m:1021 Finished mapping operation successfully... 2014-03-07 14:56:19.987 Shoopi[8149:410b] T restkit.object_mapping:RKMapperOperation.m:320 Examining keyPath '<null>' for mappable content... 2014-03-07 14:56:19.988 Shoopi[8149:410b] D restkit.object_mapping:RKMapperOperation.m:300 Found mappable data at keyPath '<null>': { code = 0; data = "{\"_id\":\"5319459fe6b6558526000001\",\"age\":\"19\",\"gender\":\"female\",\"lastname\":\"test\",\"name\":\"test\",\"password\":\"1234\",\"photo\":null,\"repeatPassword\":\"1234\",\"username\":\"test@test.cl\"}"; message = Success; } 2014-03-07 14:56:19.989 Shoopi[8149:410b] D restkit.object_mapping:RKMapperOperation.m:231 Asked to map source object { code = 0; data = "{\"_id\":\"5319459fe6b6558526000001\",\"age\":\"19\",\"gender\":\"female\",\"lastname\":\"test\",\"name\":\"test\",\"password\":\"1234\",\"photo\":null,\"repeatPassword\":\"1234\",\"username\":\"test@test.cl\"}"; message = Success; } with mapping <RKObjectMapping:0x8caafa0 objectClass=LoginResponse propertyMappings=( "<RKAttributeMapping: 0x8cab020 code => code>", "<RKAttributeMapping: 0x8cab030 message => message>", "<RKRelationshipMapping: 0x8cab240 data => data>" )> 2014-03-07 14:56:19.989 Shoopi[8149:410b] D restkit.object_mapping:RKMappingOperation.m:952 Starting mapping operation... 2014-03-07 14:56:19.990 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:953 Performing mapping operation: <RKMappingOperation 0x8ccb570> for 'LoginResponse' object. Mapping values from object { code = 0; data = "{\"_id\":\"5319459fe6b6558526000001\",\"age\":\"19\",\"gender\":\"female\",\"lastname\":\"test\",\"name\":\"test\",\"password\":\"1234\",\"photo\":null,\"repeatPassword\":\"1234\",\"username\":\"test@test.cl\"}"; message = Success; } to object <LoginResponse: 0xb9adc50> with object mapping (null) 2014-03-07 14:56:19.990 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'code' to 'code' 2014-03-07 14:56:19.990 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:572 Mapped attribute value from keyPath 'code' to 'code'. Value: 0 2014-03-07 14:56:19.990 Shoopi[8149:1007] D restkit.object_mapping:RKPropertyInspector.m:130 Cached property inspection for Class 'LoginResponse': { code = { isPrimitive = 0; keyValueCodingClass = NSNumber; name = code; }; data = { isPrimitive = 0; keyValueCodingClass = UserMapping; name = data; }; message = { isPrimitive = 0; keyValueCodingClass = NSString; name = message; }; } 2014-03-07 14:56:19.991 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:550 Mapping attribute value keyPath 'message' to 'message' 2014-03-07 14:56:19.991 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:572 Mapped attribute value from keyPath 'message' to 'message'. Value: Success 2014-03-07 14:56:19.992 Shoopi[8149:410b] D restkit.object_mapping:RKMappingOperation.m:683 Mapping one to one relationship value at keyPath 'data' to 'data' 2014-03-07 14:56:19.992 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:641 Performing nested object mapping using mapping <RKRelationshipMapping: 0x8cab240 data => data> for data: {"_id":"5319459fe6b6558526000001","age":"19","gender":"female","lastname":"test","name":"test","password":"1234","photo":null,"repeatPassword":"1234","username":"test@test.cl"} 2014-03-07 14:56:19.993 Shoopi[8149:410b] D restkit.object_mapping:RKMappingOperation.m:952 Starting mapping operation... 2014-03-07 14:56:19.993 Shoopi[8149:410b] T restkit.object_mapping:RKMappingOperation.m:953 Performing mapping operation: <RKMappingOperation 0x8ccc990> for 'UserMapping' object. Mapping values from object {"_id":"5319459fe6b6558526000001","age":"19","gender":"female","lastname":"test","name":"test","password":"1234","photo":null,"repeatPassword":"1234","username":"test@test.cl"} ({ HTTP = { request = { URL = "http://shoppi-services.herokuapp.com/public/login"; headers = { Accept = "application/json"; "Accept-Language" = "en;q=1, fr;q=0.9, de;q=0.8, zh-Hans;q=0.7, zh-Hant;q=0.6, ja;q=0.5"; "Content-Type" = "application/json; charset=utf-8"; "User-Agent" = "Shoopi/1.0 (iPhone Simulator; iOS 7.0; Scale/2.00)"; }; method = POST; }; response = { URL = "http://shoppi-services.herokuapp.com/public/login"; headers = { Connection = "keep-alive"; "Content-Length" = 250; "Content-Type" = "application/json;charset=utf-8"; Date = "Fri, 07 Mar 2014 17:56:19 GMT"; Server = "WEBrick/1.3.1 (Ruby/2.1.0/2013-12-25)"; "Set-Cookie" = "SHOPPI-TOKEN=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiRTZkY2FmNDQ2NGU1MDNhYjJmYzdl%0AMDA3ZDczOGQ0OTQ0NTI4YmFmMTE0NTY5OTU0YmFjMTE3NWNhYjE4OTFkMjAG%0AOwBGSSIUc2luYXRyYS5zZXNzaW9uBjsAVFQ%3D%0A--dafa7a330f49e7c69ca1fd8d0768a889dd2345d2; path=/; expires=Fri, 07 Mar 2014 18:56:19 -0000; HttpOnly"; Via = "1.0 proxy2.taisagroup.com (squid)"; "X-Cache" = "MISS from proxy2.taisagroup.com"; "X-Cache-Lookup" = "MISS from proxy2.taisagroup.com:3128"; "X-Content-Type-Options" = nosniff; }; }; }; mapping = { collectionIndex = "<null>"; rootKeyPath = "<null>"; }; }) to object <UserMapping: 0x8ccb720> with object mapping (null) 2014-03-07 14:56:20.045 Shoopi[8149:410b] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0xbb6e580> valueForUndefinedKey:]: this class is not key value coding-compliant for the key _id.' *** First throw call stack: ( 0 CoreFoundation 0x024e95e4 __exceptionPreprocess + 180 1 libobjc.A.dylib 0x0226c8b6 objc_exception_throw + 44 2 CoreFoundation 0x025796a1 -[NSException raise] + 17 3 Foundation 0x01f2db0a -[NSObject(NSKeyValueCoding) valueForUndefinedKey:] + 282 4 Foundation 0x01e9ab61 _NSGetUsingKeyValueGetter + 81 5 Foundation 0x01e9a19b -[NSObject(NSKeyValueCoding) valueForKey:] + 260 6 Foundation 0x01eb9c9a -[NSObject(NSKeyValueCoding) valueForKeyPath:] + 409 7 Shoopi 0x000d2571 -[RKMappingSourceObject valueForKeyPath:] + 833 8 Shoopi 0x000d7b87 -[RKMappingOperation applyAttributeMappings:] + 1671 9 Shoopi 0x000df57e -[RKMappingOperation main] + 4062 10 Foundation 0x01f41a69 -[__NSOperationInternal _start:] + 671 11 Foundation 0x01ebe798 -[NSOperation start] + 83 12 Shoopi 0x000d8a0a -[RKMappingOperation mapNestedObject:toObject:withRelationshipMapping:metadata:] + 1706 13 Shoopi 0x000d9655 -[RKMappingOperation mapOneToOneRelationshipWithValue:mapping:] + 1477 14 Shoopi 0x000dd2e6 -[RKMappingOperation applyRelationshipMappings] + 6870 15 Shoopi 0x000df620 -[RKMappingOperation main] + 4224 16 Foundation 0x01f41a69 -[__NSOperationInternal _start:] + 671 17 Foundation 0x01ebe798 -[NSOperation start] + 83 18 Shoopi 0x000ccbe5 -[RKMapperOperation mapRepresentation:toObject:atKeyPath:usingMapping:metadata:] + 1957 19 Shoopi 0x000cb460 -[RKMapperOperation mapRepresentation:atKeyPath:usingMapping:] + 1904 20 Shoopi 0x000cdddd -[RKMapperOperation mapRepresentationOrRepresentations:atKeyPath:usingMapping:] + 829 21 Shoopi 0x000ce732 -[RKMapperOperation mapSourceRepresentationWithMappingsDictionary:] + 2210 22 Shoopi 0x000cf0fb -[RKMapperOperation main] + 1403 23 Foundation 0x01f41a69 -[__NSOperationInternal _start:] + 671 24 Foundation 0x01ebe798 -[NSOperation start] + 83 25 Shoopi 0x0011f7ba -[RKObjectResponseMapperOperation performMappingWithObject:error:] + 1354 26 Shoopi 0x0011d7b3 -[RKResponseMapperOperation main] + 2371 27 Foundation 0x01f41a69 -[__NSOperationInternal _start:] + 671 28 Foundation 0x01ebe798 -[NSOperation start] + 83 29 Foundation 0x01f43d34 __NSOQSchedule_f + 62 30 libdispatch.dylib 0x0310f4b0 _dispatch_client_callout + 14 31 libdispatch.dylib 0x030fd088 _dispatch_queue_drain + 450 32 libdispatch.dylib 0x030fce85 _dispatch_queue_invoke + 126 33 libdispatch.dylib 0x030fde25 _dispatch_root_queue_drain + 83 34 libdispatch.dylib 0x030fe13d _dispatch_worker_thread2 + 39 35 libsystem_c.dylib 0x03427e72 _pthread_wqthread + 441 36 libsystem_c.dylib 0x0340fd2a start_wqthread + 30 ) libc++abi.dylib: terminating with uncaught exception of type NSException (lldb)

Regards.

Answer1:

You have a JSON string inside your JSON payload. RestKit isn't going to play nice with that. Ideally you should change the server. Otherwise you would need to read data in as the string it is and post-process it...

That post processing could use RestKit by creating and executing a RKMappingOperation, but changing the source JSON is far preferable if possible as using RKMappingOperation will make relationships harder to manage.

<hr />

Initial wrong answer, but important anyway:

You need to correct all of your path patterns and keypaths (mostly path patterns). At the moment you're asking RestKit to apply all mappings to responses and eventually (as you see) something will go wrong. You use path patterns to limit which response descriptors are applied to which responses.

Recommend

  • Javascript CORS - No 'Access-Control-Allow-Origin' header is present
  • How can I include If-None-Match header in HttpRequestMessage
  • Yii2: Finding file and getting path in a directory tree
  • Clear fused location provider's location for testing
  • Clear activity stack before launching another activity
  • NUnit 3.0 TestCase const custom object arguments
  • Angular2 Response for preflight is invalid (redirect) from some GET requests
  • How do I configure context broker accept post requests from my remote sensor?
  • What does 'Language neutral' mean with regard to MAKELANGID?
  • Parse a date string in a specific locale (not timezone!)
  • Android activity accessing service's static reference before the service is ready
  • chrome.tabs.executeScript only fires when the Developer Console is open
  • azure media services - The request body is too large and exceeds the maximum permissible limit
  • Content-Length header not returned from Pylons response
  • MVC3 Razor - ListBox pre-select not working
  • Play WS (2.2.1): post/put large request
  • Set the selected item in dropdownlist in MVC3
  • Switching to Release Build causes runtime error in Web Reference
  • ilmerge with a PFX file
  • Spring Data JPA custom method causing PropertyReferenceException
  • Display issues when we change from one jquery mobile page to another in firefox
  • Can I display google adwords (AdView) in javafx on android
  • Different response to non-authenticated users and AJAX calls
  • C# - Serializing and deserializing static member
  • Sending data from AppleScript to FileMaker records
  • Validaiting emails with Net.Mail MailAddress
  • How to apply VCL Styles to DLL-based forms in Inno Setup?
  • sending/ receiving email in Java
  • Do I've to free mysql result after storing it?
  • Warning: Can't call setState (or forceUpdate) on an unmounted component
  • Cannot Parse HTML Data Using Android / JSOUP
  • How to include full .NET prerequisite for Wix Burn installer
  • JTable with a ScrollPane misbehaving
  • Turn off referential integrity in Derby? is it possible?
  • Is it possible to post an object from jquery to bottle.py?
  • unknown Exception android
  • Can't mass-assign protected attributes when import data from csv file
  • JaxB to read class hierarchy
  • failed to connect to specific WiFi in android programmatically
  • How can I use threading to 'tick' a timer to be accessed by other threads?