0
votes

In my app I have a Settings class which maps a server response using RestKit.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ...

    [manager.router.routeSet addRoute:[RKRoute routeWithClass:[Settings class]
                                              pathPattern:kAPIPathSettingsAllRequest
                                                   method:RKRequestMethodGET]];
    [manager.router.routeSet addRoute:[RKRoute routeWithClass:[Settings class]
                                              pathPattern:kAPIPathSettingsAllRequest
                                                   method:RKRequestMethodPOST]];
    ...
}

Load Settings:

@property (nonatomic, retain) Settings *settings;

- (void)loadSettings
{
    [[RKObjectManager sharedManager] getObject:_settings
                                      path:nil
                                parameters:SessionTokenDictionary()
                                   success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult)
     {
         RKLogInfo(@"Settings received: %@", mappingResult.firstObject);

         [self.tableView reloadData];

     }
                                   failure:^(RKObjectRequestOperation *operation, NSError *error)
     {
         RKLogError(@"Failed getting settings: %@", error);
     }];
}

Settings.h

#import <Foundation/Foundation.h>
#import "RKSupportDelegate.h"

@interface Settings : NSObject <RKSupportDelegate>
@property (nonatomic, assign) BOOL flightStatusUpdated;
@property (nonatomic, assign) BOOL friendInTheCity;
@property (nonatomic, assign) BOOL friendRequest;

Settings.m

#import <RestKit/RestKit.h>
#import "Settings.h"

@implementation Settings

+ (RKMapping *)mapping
{
    RKObjectMapping* responseMapping = [RKObjectMapping mappingForClass:[self class]];
    [responseMapping addAttributeMappingsFromDictionary:@{
        @"push_friends": @"friendRequest",
        @"my_flight_status": @"flightStatusUpdated",                         
        @"meet_friends": @"friendInTheCity",
    }];
    return responseMapping;
}

+ (void)generateRKDescriptors
{
    /*
     * Response
     */

    RKResponseDescriptor *responseDescriptor;
    NSIndexSet *codesSet = [NSIndexSet indexSetWithIndexesInRange:RKStatusCodeRangeForClass(RKStatusCodeClassSuccessful)];
    responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[self mapping]
                                                                  method:RKRequestMethodAny
                                                             pathPattern:nil
                                                                 keyPath:@"settings"
                                                             statusCodes:codesSet];
    [[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];

    /*
     * Request
     */

    RKObjectMapping *requestMapping = [RKObjectMapping requestMapping];
    [requestMapping addAttributeMappingsFromDictionary:@{
        @"friendRequest": @"push_friends",
        @"flightStatusUpdated": @"my_flight_status",                         
        @"friendInTheCity": @"meet_friends",
    }];


    RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:requestMapping objectClass:[self class] rootKeyPath:nil method:RKRequestMethodAny];

    [[RKObjectManager sharedManager] addRequestDescriptor:requestDescriptor];

}

Response:

2014-06-23 15:23:22.369 App[16622:410b] D restkit.network:RKResponseMapperOperation.m:463 Mapping HTTP response to unmanaged target object with `RKManagedObjectResponseMapperOperation`: <Settings: 0x1a484470>
2014-06-23 15:23:22.624 App[16622:700f] T restkit.network:RKObjectRequestOperation.m:218 GET '<.....>' (200 OK / 0 objects) [request=0.0000s mapping=0.0114s total=0.5428s]:
response.headers={
    "Access-Control-Allow-Origin" = "*";
    "Cache-Control" = "private, no-cache, no-store, must-revalidate";
    Connection = "Keep-Alive";
    "Content-Length" = 390;
    "Content-Type" = "application/json; charset=UTF-8";
    Date = "Mon, 23 Jun 2014 13:23:22 GMT";
    Expires = "Mon, 26 Jul 1997 05:00:00 GMT";
    "Keep-Alive" = "timeout=5, max=100";
    Pragma = "no-cache";
    Server = Apache;
}
response.body={
    "settings": {
        "push_friends": false,
        "my_flight_status": false,
        "meet_friends": false,
  }
}
2014-06-23 15:23:23.105 App[16622:60b] T restkit.network:RKObjectRequestOperation.m:148 GET '<.....>':
request.headers={
    Accept = "application/json";
    "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" = "App/1.5.1 (iPhone; iOS 7.1.1; Scale/2.00)";
}
request.body=(null)
2014-06-23 15:23:23.123 App[16622:60b] I app:SettingsViewController.m:370 Settings received: (null)

What I do not understand is why the mapping doesn't work which apparently leads to:

2014-06-23 15:23:23.123 App[16622:60b] I app:SettingsViewController.m:370 Settings received: (null)

and this:

2014-06-23 15:23:22.369 App[16622:410b] D restkit.network:RKResponseMapperOperation.m:463 Mapping HTTP response to unmanaged target object with 'RKManagedObjectResponseMapperOperation': <Settings: 0x1a484470>

I hope somebody can help me out here. Thanks a lot!

Update: Mapping Trace Log:

2014-06-23 16:47:47.363 App[17122:3e13] D restkit.object_mapping:RKMapperOperation.m:378 Executing mapping operation for representation: {
    settings =     {
        "meet_friends" = 0;
        "my_flight_status" = 0;
        "push_friends" = 0;
    };
}
 and targetObject: <Settings: 0x18c21860>
2014-06-23 16:47:47.366 App[17122:3e13] T restkit.object_mapping:RKMapperOperation.m:321 Examining keyPath '' for mappable content...
2014-06-23 16:47:47.368 App[17122:3e13] D restkit.object_mapping:RKMapperOperation.m:301 Found mappable data at keyPath '': {
    settings =     {
        "push_friends" = 0;
        "my_flight_status" = 0;
        "meet_friends" = 0;
    };
}
2014-06-23 16:54:29.044 App[17122:4433] D restkit.object_mapping:RKMapperOperation.m:230 Asked to map source object {
settings =     {
    "push_friends" = 0;
    "my_flight_status" = 0;
    "meet_friends" = 0;
};
} with mapping <RKObjectMapping:0x155c36f0 objectClass=User propertyMappings=(
"<RKAttributeMapping: 0x155c3740 countries => countriesCount>",
"<RKAttributeMapping: 0x155c3910 type => type>",
"<RKAttributeMapping: 0x155c3990 requested_me => requestedMe>",
"<RKAttributeMapping: 0x155c3a30 last_name => lastName>",
"<RKAttributeMapping: 0x155c39f0 gender => gender>",
"<RKAttributeMapping: 0x155c3a10 cities => citiesCount>",
"<RKAttributeMapping: 0x155c3da0 first_name => firstName>",
"<RKAttributeMapping: 0x155c4000 uid => uid>",
"<RKAttributeMapping: 0x155c4020 status => status>",
"<RKAttributeMapping: 0x155c4040 name => name>",
"<RKAttributeMapping: 0x155c3f60 miles => miles>",
"<RKAttributeMapping: 0x155c3f80 level => level>",
"<RKAttributeMapping: 0x155c4060 city => city>",
"<RKAttributeMapping: 0x155c4080 email => email>"
)>
2014-06-23 16:54:29.078 App[17122:4433] D restkit.object_mapping:RKMappingOperation.m:859 Starting mapping operation...
2014-06-23 16:54:29.143 App[17122:4433] T restkit.object_mapping:RKMappingOperation.m:860 Performing mapping operation: <RKMappingOperation 0x15781140> for 'User' object. Mapping values from object {
settings =     {
    "push_friends" = 0;
    "my_flight_status" = 0;
    "meet_friends" = 0;
};
} to object <User: uid=0, status=0, name=(null), miles=0, city=(null), level=(null), friend status:(null), statsInfo:(null), citiesCount:0, countriesCount:0> with object mapping (null)
2014-06-23 16:54:29.162 App[17122:4433] T restkit.object_mapping:RKMappingOperation.m:518 Did not find mappable attribute value keyPath 'countries'
2014-06-23 16:54:29.195 App[17122:4433] T restkit.object_mapping:RKMappingOperation.m:518 Did not find mappable attribute value keyPath 'home_airport'
2014-06-23 16:54:29.205 App[17122:4433] T restkit.object_mapping:RKMappingOperation.m:518 Did not find mappable attribute value keyPath 'isfriend'
2014-06-23 16:54:29.329 App[17122:4433] T restkit.object_mapping:RKMappingOperation.m:518 Did not find mappable attribute value keyPath 'name'
...
1
You are seeing request and response in the log and thinking they are the same thing. In the trace log for mapping, what does it say is happening? - Wain
You are right. I totally didn't see that they are different. My bad. But the problem still remains. - freshking
You need to examine the mapping trace log instead of the network trace log. The code looks reasonable at first glance. - Wain
I updated the description for the mapping trace log. It seems like it is trying to map to the User class. I don't see how it can come to that. - freshking

1 Answers

1
votes

When you create the response descriptor your set:

pathPattern:nil

and presumably you have a number of other response descriptors which do the same. You must also have some response descriptors with a nil key path.

This means that RestKit can't filter the response descriptors properly and will try to apply all that match - which results in some bad and meaningless mappings.

So, apply the tightest path pattern and key path specification you can to your response descriptors to prevent this and to improve performance.