Reputation: 5150
I'm using RestKit and this is how I initialize it and add routes and descriptors:
- (void)initRestClient
{
NSURL *baseURL = [NSURL URLWithString:kSomeBaseURL];
self.manager = [RKObjectManager managerWithBaseURL:baseURL];
[self.manager setRequestSerializationMIMEType:RKMIMETypeJSON];
[self.manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[self.manager addResponseDescriptorsFromArray:[RKObjectManager sharedManager].responseDescriptors];
[self.manager addRequestDescriptorsFromArray:[RKObjectManager sharedManager].requestDescriptors];
[self.manager.HTTPClient.operationQueue setMaxConcurrentOperationCount:5];
[RKObjectManager setSharedManager:self.manager];
// AFHTTPClient *client = [RKObjectManager sharedManager].HTTPClient;
[self initRoutes];
[self initMappingObjectsAndDiscriptors];
}
- (void)initRoutes
{
RKRoute *bannersRoute = [RKRoute routeWithClass:[RKBanner class] pathPattern:@"Banners?categoryID=:categoryID" method:RKRequestMethodGET];
bannersRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:bannersRoute];
RKRoute *branchesRoute = [RKRoute routeWithClass:[RKBranches class] pathPattern:@"Branches?city=:city&type=:type" method:RKRequestMethodGET];
branchesRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:branchesRoute];
RKRoute *shortTokenRoute = [RKRoute routeWithClass:[RKShortToken class] pathPattern:@"users/login/quick/shortToken?phone=:phone&extraCode=:extraCode" method:RKRequestMethodGET];
shortTokenRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:shortTokenRoute];
RKRoute *longTokenRoute = [RKRoute routeWithClass:[RKLongToken class] pathPattern:@"users/login/quick/userDetails?shortToken=:shortToken" method:RKRequestMethodGET];
longTokenRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:longTokenRoute];
}
- (void)initMappingObjectsAndDiscriptors
{
RKObjectMapping *bannerMapping = [RKObjectMapping mappingForClass:[RKBanner class]];
[bannerMapping addAttributeMappingsFromDictionary:[RKBanner getAttributes]];
RKResponseDescriptor *bannerDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:bannerMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"Banners" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectMapping *branchesMapping = [RKObjectMapping mappingForClass:[RKBranches class]];
[branchesMapping addAttributeMappingsFromDictionary:[RKBranches getAttributes]];
RKResponseDescriptor *branchesDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:branchesMapping method:RKRequestMethodGET pathPattern:nil keyPath:@"Branches" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectMapping *shortTokenMapping = [RKObjectMapping mappingForClass:[RKShortToken class]];
[shortTokenMapping addAttributeMappingsFromDictionary:[RKShortToken getAttributes]];
RKResponseDescriptor *shortTokenDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:shortTokenMapping method:RKRequestMethodGET pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKObjectMapping *longTokenMapping = [RKObjectMapping mappingForClass:[RKLongToken class]];
[longTokenMapping addAttributeMappingsFromDictionary:[RKLongToken getAttributes]];
// longTokenMapping.setDefaultValueForMissingAttributes = YES;
// longTokenMapping.setNilForMissingRelationships = YES;
RKResponseDescriptor *longTokenDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:longTokenMapping method:RKRequestMethodGET pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.manager addResponseDescriptorsFromArray:@[bannerDescriptor, branchesDescriptor, shortTokenDescriptor, longTokenDescriptor]];
}
This is how each one of the classes is build:
@interface RKBanner : NSObject
@property (strong, nonatomic) NSNumber *idNum;
@property (strong, nonatomic) NSString *name;
@property (strong, nonatomic) NSString *addressURL;
@property (strong, nonatomic) NSString *bannerPosition;
@property (strong, nonatomic) NSString *imageALT;
@property (strong, nonatomic) NSNumber *imageHeight;
@property (strong, nonatomic) NSString *imageURL;
@property (strong, nonatomic) NSNumber *imageWidth;
@property (strong, nonatomic) NSString *subtitle;
@property (strong, nonatomic) NSString *targetURL;
@property (strong, nonatomic) NSString *textURL;
@property (strong, nonatomic) NSString *title;
+ (NSDictionary*)getAttributes;
@end
@implementation RKBanner
+ (NSDictionary*)getAttributes
{
return [NSDictionary dictionaryWithObjects:@[@"idNum", @"name", @"addressURL", @"bannerPosition", @"imageALT", @"imageHeight",
@"imageURL", @"imageWidth", @"subtitle", @"targetURL", @"textURL", @"title"]
forKeys:@[@"ID", @"Name", @"AddressURL", @"BannerPosition", @"ImageALT", @"ImageHeight",
@"ImageURL", @"ImageWidth", @"SubTitle", @"TargetURL", @"TextURL", @"Title"]];
}
@end
@interface RKBranches : NSObject
@property (strong, nonatomic) NSNumber *idNum;
@property (strong, nonatomic) NSString *branchTitle;
@property (strong, nonatomic) NSString *address;
@property (strong, nonatomic) NSNumber *branchType;
@property (strong, nonatomic) NSString *city;
@property (strong, nonatomic) NSString *fax;
@property (assign, nonatomic) BOOL isCanOrder;
@property (assign, nonatomic) BOOL isMe;
@property (strong, nonatomic) NSString *openHours;
@property (strong, nonatomic) NSString *orderCode;
@property (strong, nonatomic) NSString *phone;
@property (strong, nonatomic) NSString *remarks;
+ (NSDictionary*)getAttributes;
@end
@implementation RKBranches
+ (NSDictionary*)getAttributes
{
return [NSDictionary dictionaryWithObjects:@[@"idNum", @"branchTitle", @"address", @"branchType", @"city", @"fax",
@"isCanOrder", @"isMe", @"openHours", @"orderCode", @"phone", @"remarks"]
forKeys:@[@"ID", @"Name", @"Address", @"BranchType", @"City", @"Fax",
@"IsCanOrder", @"IsMe", @"OpenHours", @"OrderCode", @"Phone", @"Remarks"]];
}
@end
@interface RKShortToken : NSObject
@property (strong, nonatomic) NSString *responseError;
@property (strong, nonatomic) NSString *shortToken;
+ (NSDictionary*)getAttributes;
@end
@implementation RKShortToken
+ (NSDictionary*)getAttributes
{
return [NSDictionary dictionaryWithObjects:@[@"responseError", @"shortToken"]
forKeys:@[@"responseError", @"shortToken"]];
}
@end
@interface RKLongToken : NSObject
@property (strong, nonatomic) NSString *responseError;
@property (strong, nonatomic) NSString *responseMessage;
@property (strong, nonatomic) NSString *responseHttpCode;
@property (strong, nonatomic) NSString *responseUserMessage;
@property (strong, nonatomic) NSString *abroadInd;
@property (strong, nonatomic) NSString *accountType;
@property (strong, nonatomic) NSString *customerID;
@property (strong, nonatomic) NSString *longToken;
+ (NSDictionary*)getAttributes;
@end
@implementation RKLongToken
+ (NSDictionary*)getAttributes
{
return [NSDictionary dictionaryWithObjects:@[@"responseError", @"responseMessage", @"responseHttpCode", @"responseUserMessage",
@"abroadInd", @"accountType", @"customerID", @"longToken"]
forKeys:@[@"responseError", @"responseError.DeveloperMessage", @"responseError.HttpCode", @"responseError.UserMessage",
@"abroadInd", @"accountType", @"customerId", @"longToken"]];
}
@end
Than when I try to call RKShortToken, I get a good response, but the object that I get is RKLongToken:
- (void)quickLoginWithTelephone:(NSString*)telephone extraCode:(NSString *)extraCode completionBlock:(quickLoginExtraCodeCompletionBlock)success
{
NSDictionary *params = @{ @"phone" : telephone, @"extraCode" : extraCode };
[[RKObjectManager sharedManager] getObjectsAtPath:@"users/login/quick/shortToken?"
parameters:params
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(@"%@", operation.HTTPRequestOperation.responseString);
NSLog(@"%@", mappingResult.array);
success(YES);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"Error occurred.");
}];
}
Here is the logs:
2014-01-06 15:46:01.428 Online[8796:60b] I restkit.network:RKObjectRequestOperation.m:180 GET 'http://10.174.10.35/service/service.svc/users/login/quick/shortToken?&extraCode=null&phone=0505717596'
2014-01-06 15:50:03.999 Online[8796:60b] {"responseError":null,"shortToken":"I55933325601458654742"}
2014-01-06 15:46:01.577 Online[8796:60b] (
"<RKLongToken: 0x14dd3a50>"
)
2014-01-06 15:46:04.490 Online[8796:1403] I restkit.network:RKObjectRequestOperation.m:250 GET 'http://10.174.10.35/service/service.svc/users/login/quick/shortToken?&extraCode=null&phone=0505717596' (200 OK / 1 objects) [request=3.0587s mapping=0.0030s total=3.1129s]
What seems to be the problem here?
UPDATE:
I've added pathPattern
to the descriptor as @Wain told me to, but now I'm getting an error. It looks like this:
"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: Banners, Branches, BranchTypes, Cities, MenuList
The representation inputted to the mapper was found to contain nested object representations at the following key paths: responseError, shortToken
This likely indicates that you have misconfigured the key paths for your mappings., NSLocalizedDescription=No mappable object representations were found at the key paths searched., keyPath=null}`
Upvotes: 2
Views: 933
Reputation: 5150
The correct way to do that is first to initialize the RestKit client:
NSURL *baseURL = [NSURL URLWithString:kServiceBaseURL];
self.manager = [RKObjectManager managerWithBaseURL:baseURL];
[self.manager setRequestSerializationMIMEType:RKMIMETypeJSON];
[self.manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[self.manager addResponseDescriptorsFromArray:[RKObjectManager sharedManager].responseDescriptors];
[self.manager addRequestDescriptorsFromArray:[RKObjectManager sharedManager].requestDescriptors];
[self.manager.HTTPClient.operationQueue setMaxConcurrentOperationCount:5];
[RKObjectManager setSharedManager:self.manager];
Than to initialize the Routes that you want:
RKRoute *shortTokenRoute = [RKRoute routeWithClass:[RKShortToken class] pathPattern:@"users/login/quick/shortToken" method:RKRequestMethodGET];
shortTokenRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:shortTokenRoute];
Than to create a reponseDescriptor:
RKObjectMapping *shortTokenMapping = [RKObjectMapping mappingForClass:[RKShortToken class]];
[shortTokenMapping addAttributeMappingsFromDictionary:@{ @"responseError" : @"responseError", @"shortToken" : @"shortToken" }];
RKResponseDescriptor *shortTokenDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:shortTokenMapping
method:RKRequestMethodAny
pathPattern:@"users/login/quick/shortToken"
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager] addResponseDescriptor:shortTokenDescriptor];
Than the request:
NSDictionary *params = @{ @"phone" : telephone, @"extraCode" : extraCode };
[[RKObjectManager sharedManager] getObject:[[RKShortToken alloc] init]
path:@"users/login/quick/shortToken"
parameters:params
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(@"%@", operation.HTTPRequestOperation.responseString);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"%@", error.localizedDescription);
}];
Enjoy.
Upvotes: 0
Reputation: 119021
All of your response descriptors have pathPattern:nil
, so RestKit can't filter and will apply all of them and see what happens. So, for all of your JSON you will get multiple objects containing only the parts of each mapping that match the JSON.
To fix, add path patterns to allow RestKit to determine which response descriptor matches each of your requests.
Upvotes: 1