我可以混合使用 RKEntityMapping 和 RKObjectMapping
Posted
技术标签:
【中文标题】我可以混合使用 RKEntityMapping 和 RKObjectMapping【英文标题】:Can I mix RKEntityMapping and RKObjectMapping 【发布时间】:2014-05-07 15:45:29 【问题描述】:他们似乎在这里做了一个解决方法: Relationship between RKObjectMapping and RKEntityMapping
我可以在不采取任何解决方法的情况下混合它们吗? 谢谢。
编辑:在这里我添加了一个示例 JSON。我想在 Core Data 中存储的是两个实体 Region,但没有关于 resultCode 或 resultDescription。这就是我问我是否可以混合它们的原因。
"resultCode": 0,
"resultDescription": "OK",
"resultContent": [
"region_id": 0,
"description": "USA"
,
"region_id": 1,
"description": "Europe"
]
【问题讨论】:
如何混合它们 - 提供 JSON 和您的数据对象的详细信息 你好 Wain,请参阅说明。 你的问题的答案是什么? 【参考方案1】:当我使用旧版 API 时,我自己也遇到了同样的问题。以下是我的解决方案:
响应json:
"resultCode": 0,
"resultDescription": "OK",
"resultContent": [
"region_id": 0,
"description": "USA"
,
"region_id": 1,
"description": "Europe"
]
这个问题有两种解决方案:
解决方案 #1:使用带有 @""
键路径的对象映射
假设您已经拥有属性名称与 json 键名称相同的托管类 Region
@interface Response
@property (nonatomic) NSInteger resultCode;
@property (nonatomic, strong) NSString resultDescription;
@end
@implementation Response
// Make it KV compliant
@end
映射
// Response map
RKObjectMapping* resMap = [RKObjectMapping mappingForClass: [Response class]];
[resMap addAttributeMappingsFromArray: @[@"resultCode", @"resultDescription"]];
responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:resMap method: RKRequestMethodAny pathPattern:@"" keyPath:@"" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
// Region map
RKEntityMapping* mapping = [RKEntityMapping mappingForEntityForName: name inManagedObjectStore:[[RKObjectManager sharedManager] managedObjectStore]];
[mapping addAttributeMappingsFromArray: @[@"region_id", @"description"]];
descriptor = [RKResponseDescriptor responseDescriptorWithMapping:mapping method: RKRequestMethodAny pathPattern:@"/api/regions" keyPath:@"resultContent" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
得到结果
Response* res = [[mappingResult dictionary] objectForKey:[NSNull null]];
NSArray* reg = [[mappingResult dictionary] objectForKey:@"resultContent"];
解决方案 #2:使用序列化
您可以注册您的 RKSerialization
实现
[RKMIMETypeSerialization registerClass:[NKJsonSerialization class]
forMIMEType:RKMIMETypeJSON];
在您的序列化实现中,您可以检查响应是否为错误响应并创建一个NSError
对象,然后将其发送回 Restkit。
@implementation NKJsonSerialization
+ (id)objectFromData:(NSData *)data error:(NSError **)error
NSError* serializingError = nil;
NSMutableDictionary* jsonObject = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers
error:&serializingError];
// Process if there is no error
if (!serializingError)
NSString* resCodeStr = [jsonObject objectForKey:@"resultCode"];
if ([resCodeStr intValue] != 0)
// Create your NSError for your domain, contain information about response err
serializingError == <#new created error#>
jsonObject = nil;
else
[jsonObject removeObjectForKey: @"resultCode"];
[jsonObject removeObjectForKey: @"resultDescription"];
serializingError = nil;
*error = serializingError;
return jsonObject;
如果您的响应包含错误代码,在您的请求回调中,RestKit 将返回一个 NSError 对象,其中底层错误是您刚刚在序列化期间创建的错误。
此解决方案的美妙之处在于您不必关心映射响应状态。错误的响应将(应该)作为 NSError 处理。
如果 json 对象在顶层包含数据对象(键路径 @""),您仍然可以使用映射来获取它而不会发生键冲突,就像在解决方案 #1 中发生的那样。
【讨论】:
/api/region.它来自哪里 它应该是你的请求路径。【参考方案2】:我不确定您到底在问什么。RKEntityMapping 用于映射到 Core Data 实体,而 RKObjectMapping 仅用于映射到常规对象表示。所以也许问题是,您是否使用 Core Data?
【讨论】:
您好 EAB,请参阅说明。【参考方案3】:在这种情况下,您不需要混合它们。创建响应描述符时,您将键路径设置为 resultContent
并仅使用实体映射。
可以通过某些方式混合映射类型,但这通常需要根据具体情况进行考虑。通常,您会使用多个响应描述符来保持映射分离,然后将结果合并为后处理。
【讨论】:
好主意,这也是一种可能,但据我了解,我还需要创建一个动态映射来捕获错误。 您的问题显示为您不想要错误信息。您可以使用动态映射或 2 个响应描述符。【参考方案4】:您需要为 RKObjectMapping 和 RKEntityMapping 对象定义两个单独的描述符,在您的情况下为 StatusMapping 和 RegionMapping 然后将它们添加到 ObjectManager,它就像魅力一样工作(我给你示例代码和类来实现这一点):
像这样定义 ResponseStatus 类:
//...
ResponseStatus.h
//...
@interface ResponseStatus : NSObject
@property (nonatomic) BOOL resultCode;
@property (nonatomic, strong) NSString *resultDescription;
+ (RKObjectMapping *)rkObjectMappingForResponse:(BOOL)includeAll;
+ (RKObjectMapping *)rkObjectMappingForRequest:(BOOL)includeAll;
+ (NSDictionary *)rkAttributeMappingsDictionary:(BOOL)request includeAll:(BOOL)includeAll;
@end
//...
ResponseStatus.m
//...
@implementation ResponseStatus
+ (RKObjectMapping *)rkObjectMappingForResponse:(BOOL)includeAll
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[ResponseStatus class]];
[mapping addAttributeMappingsFromDictionary:[self rkAttributeMappingsDictionary:NO includeAll:includeAll]];
if (includeAll)
return mapping;
+ (RKObjectMapping *)rkObjectMappingForRequest:(BOOL)includeAll
RKObjectMapping *mapping = [RKObjectMapping requestMapping];
[mapping addAttributeMappingsFromDictionary:[self rkAttributeMappingsDictionary:YES includeAll:includeAll]];
if (includeAll)
return mapping;
+ (NSDictionary *)rkAttributeMappingsDictionary:(BOOL)request includeAll:(BOOL)includeAll
NSMutableDictionary *dic = [NSMutableDictionary dictionary];
if (includeAll)
[dic addEntriesFromDictionary:@
@"resultCode": @"resultCode",
@"resultDescription": @"resultDescription",
];
return dic;
@end
为您的 ResponseStatus(结果)定义描述符映射
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful); // Anything in 2xx
RKResponseDescriptor *statusResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[ResponseStatus rkObjectMappingForResponse:YES] method:RKRequestMethodAny pathPattern:nil keyPath:@"" statusCodes:statusCodes];
为你的 RKEntityMapping 定义一个描述符映射
RKResponseDescriptor *gameResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:[Game rkEntityMappingForResponse:YES] method:RKRequestMethodAny pathPattern:nil keyPath:@"games" statusCodes:statusCodes];
向 objectManager 添加响应描述符
[objectManager addResponseDescriptorsFromArray:@[gameResponseDescriptor, statusResponseDescriptor]];
这是处理映射结果的方法
RKObjectRequestOperation *operation = [objectManager managedObjectRequestOperationWithRequest:requestObject managedObjectContext:managedObjectContext success: ^(RKObjectRequestOperation *operation, RKMappingResult *result)
if ([RKUtils isResponseStatusError:[result array]])
//..
failure: ^(RKObjectRequestOperation *operation, NSError *error)
NSLog(@"Failed with error: %@", [error localizedDescription]);
];
+ (BOOL)isResponseStatusError:(NSArray *)itemsList
if ([itemsList count] != 1)
return NO;
id object = itemsList[0];
if ([object isKindOfClass:[ResponseStatus class]])
ResponseStatus *responseStatus = object;
if (!responseStatus.resultCode)
NSLog(@"Error : %@", responseStatus.message);
return YES;
return NO;
并进行 REST 调用,希望对您有所帮助。
【讨论】:
你如何处理映射结果? 您不应该假设ResponseStatus
将作为数组中的第一个对象出现。经过快速搜索,我认为这应该是处理结果的更正确方法:[[result dictionary] objectForKey:[NSNull null]]
@""
处的根对象将设置为 NSNull
键(已测试)【参考方案5】:
好的,经过几次测试,我意识到RestKit将RKEntityMapping保存在核心数据中,而不是RKObjectMapping。它完美地工作。我喜欢 RestKit :)
【讨论】:
您介意分享您的映射代码吗?有人可能会觉得它有帮助 你告诉我们的一样。只是不要做任何事情。如果您想将它们保存在核心数据中,请声明 RKObjectMapping;如果您不想保存它们,请声明 RKEntityMapping。 RestKit 很棒。以上是关于我可以混合使用 RKEntityMapping 和 RKObjectMapping的主要内容,如果未能解决你的问题,请参考以下文章
通过主键与 RKObjectMapping 和 RKEntityMapping 的关系
RKEntityMapping JSON 数组 RKResponseDescriptor 键路径问题可能