如何在 Restkit 中映射自定义错误键?

How do I map custom error keys in Restkit?

当用户在我们的服务器上成功注册时,它会返回 200 状态代码和 JSON 有效负载,如下所示:

{
    "error": null,
    "result": {
        "auth": {
            "created_utc": 1420740197,
            "device_token": "rQZJddrbD5tyEpznb8bVKeGlHqRNGyvOgDR;tQJBkpkfAXO6DQ4lNiG17lzu6IDc0hVBfR3RrN9o0txRQIYAa6fnf5d9LNaSRDMk9LrplgkITuMC37v;;;rvG35CJvV7dWZ5TQVYUWeHwAABvKvzTRpSDw5Qg9jQrmiUHLZptegFY=76421420740197"
        },
        "display_name": "a",
        "email": "a@a.com",
        "user_id": 7642,
        "username": "a"
    }
}

但是如果 a@a.com 尝试再次注册,它会返回一个 400 状态代码和一个 JSON 负载,如下所示:

{
    "error": {
        "code": 805,
        "message": "there is another user with that username"
    },
    "result": null
}

我尝试映射错误,这样当 Restkit return 出现错误时,我会收到消息和代码。这些是我尝试这样做的方法:

RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"error.message" toKeyPath:@"errorMessage"]];

RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];

[self.objectManager addResponseDescriptor:errorDescriptor];

这显然只是将错误的消息部分发送到 return,输出为:

Error Domain=org.restkit.RestKit.ErrorDomain Code=1004 "there is another user with that username" UserInfo=0x7feefcf8a730 {RKObjectMapperErrorObjectsKey=(
"there is another user with that username"
), NSLocalizedDescription=there is another user with that username}

然后我尝试制作 RKErrorMessage 的子类:

#import "RKErrorMessage.h"

@interface TAG_RKErrorMessage : RKErrorMessage

@property (strong, nonatomic) NSNumber *errorCode;

@end

并将映射更改为:

RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[TAG_RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"error.message" toKeyPath:@"errorMessage"]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"error.code" toKeyPath:@"errorCode"]];

这导致了完全相同的输出:

Error Domain=org.restkit.RestKit.ErrorDomain Code=1004 "there is another user with that username" UserInfo=0x7fa16c627ce0 {RKObjectMapperErrorObjectsKey=(
"there is another user with that username"
), NSLocalizedDescription=there is another user with that username}

所以最后我尝试了这个映射,至少尝试让字典显示为 NSErroruserInfo:

RKObjectMapperErrorObjectsKey
RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:@"error" toKeyPath:@"errorMessage"]];

这导致了这个输出:

Error Domain=org.restkit.RestKit.ErrorDomain Code=1004 "<null>" UserInfo=0x7ff8abe678e0 {RKObjectMapperErrorObjectsKey=(
(null)
), NSLocalizedDescription=<null>}

现在我卡在了这一点上。我如何映射服务器错误响应的键,以便我可以访问 returned 的 code 以及作为两个单独值的 message

您可能已经正确映射了 TAG_RKErrorMessage 实例。您是否尝试从给定的 NSError 中提取它?您可以使用 RKObjectMapperErrorObjectsKey 作为 NSError 的 userInfo 字典上的键来获取所有映射错误消息的数组:

NSArray* objectMapperErrorObjectsArray = [error.userInfo objectForKey:RKObjectMapperErrorObjectsKey];

然后您可以遍历该数组以检查每个错误是否符合您要响应的条件,例如,如果您想要使用错误消息 "Invalid token" 响应 403 响应代码,您可以这样做:

NSArray* objectMapperErrorObjectsArray = [error.userInfo objectForKey:RKObjectMapperErrorObjectsKey];
for (RKErrorMessage* objectMapperErrorObject in objectMapperErrorObjectsArray)
{
    if ([objectMapperErrorObject.errorMessage isEqual:@"Invalid token"])
    {
        if (operation.HTTPRequestOperation.response.statusCode == 403)
        {
            //Code to handle a 403 response status code when error message is "Invalid token".
        }
    }
}

提示:如果你想使用内置的RKErrorMessage而不创建任何子类,你可以将所有错误JSON属性映射到RKErrorMessage.userInfo 这样:

Objective-C:

RKObjectMapping *errorMapping = [RKObjectMapping mappingForClass:[RKErrorMessage class]];
[errorMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"userInfo"]];

RKResponseDescriptor *errorDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:errorMapping method:RKRequestMethodAny pathPattern:nil keyPath:"error" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassClientError)];

Swift:

let errorMapping = RKObjectMapping(forClass: RKErrorMessage.self);
errorMapping.addPropertyMapping(RKAttributeMapping(fromKeyPath: nil, toKeyPath: "userInfo"));

let errorResponseDescriptor = RKResponseDescriptor(
    mapping: errorMapping,
    method: RKRequestMethod.Any,
    pathPattern: nil,
    keyPath: "error", 
    statusCodes: RKStatusCodeIndexSetForClass(UInt(RKStatusCodeClassClientError)))
);