RestKit 映射错误的对象
Posted
技术标签:
【中文标题】RestKit 映射错误的对象【英文标题】:RestKit mapping the wrong object 【发布时间】:2014-01-06 13:51:45 【问题描述】:我正在使用 RestKit,这就是我初始化它并添加路由和描述符的方式:
- (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]];
这是每个类的构建方式:
@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
当我尝试调用 RKShortToken 时,我得到了很好的响应,但我得到的对象是 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.");
];
这是日志:
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]
这里似乎有什么问题?
更新:
我已经按照@Wain 告诉我的那样在描述符中添加了pathPattern
,但现在我遇到了一个错误。它看起来像这样:
"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`
【问题讨论】:
【参考方案1】:您的所有响应描述符都有pathPattern:nil
,因此RestKit 无法过滤并将应用所有这些描述符并查看会发生什么。因此,对于所有 JSON,您将获得多个对象,其中仅包含与 JSON 匹配的每个映射的部分。
要解决此问题,请添加路径模式以允许 RestKit 确定哪个响应描述符与您的每个请求匹配。
【讨论】:
但是我已经在顶部的 RKRoute 有 pathPattern,当我将相同的 pathPattern 放在描述符中时它不会返回任何内容.. 响应描述符需要指定路径模式(以匹配路由)。 我将它们与路线匹配,但仍然没有任何反应。我只是不知道我做错了什么。请求很好,但返回对象始终是我添加的最后一个描述符对象。例如,我最后添加了 RKLongToken,所以当我请求 RKShortToken 时,它给了我一个 RKLongToken 对象数组......我只是想不出什么是发出请求的正确方法。 您应该为每个匹配路径模式的响应描述符获取一个对象。打开映射的跟踪日志,它应该为您提供每个被处理的响应描述符的详细信息。 我只是无法弄清楚似乎是什么问题。您能私下帮助我(电子邮件或其他方式)然后我们在这里发布答案吗?【参考方案2】:正确的做法是先初始化RestKit客户端:
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];
比初始化你想要的路由:
RKRoute *shortTokenRoute = [RKRoute routeWithClass:[RKShortToken class] pathPattern:@"users/login/quick/shortToken" method:RKRequestMethodGET];
shortTokenRoute.shouldEscapePath = YES;
[self.manager.router.routeSet addRoute:shortTokenRoute];
比创建一个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];
比请求:
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);
];
享受吧。
【讨论】:
以上是关于RestKit 映射错误的对象的主要内容,如果未能解决你的问题,请参考以下文章
RestKit 映射错误“无法将对象集合映射到非可变集合。”