我可以混合RKEntityMapping和RKObjectMapping

时间:2014-05-07 15:45:29

标签: restkit restkit-0.20

在这里他们似乎做了一个解决方法: 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" } ] }

5 个答案:

答案 0 :(得分:1)

我不确定你究竟在问什么... RKEntityMapping用于映射到Core Data实体,而RKObjectMapping用于映射到常规对象表示。所以问题可能是,您是否正在使用Core Data?

答案 1 :(得分:1)

您需要为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;
}

并打个电话,希望有所帮助。

答案 2 :(得分:1)

在这种情况下,您无需混合它们。创建响应描述符时,将关键路径设置为resultContent,并使用实体映射。

可以在某些方面混合映射类型,但这通常需要根据具体情况进行考虑。通常,您将使用多个响应描述符来保持映射分离,然后将结果组合为后期处理。

答案 3 :(得分: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中一样。

答案 4 :(得分:0)

好的,经过几次测试后,我意识到RestKit将RKEntityMapping保存在核心数据中,而不是RKObjectMapping。它完美地运作。我喜欢RestKit :))