【问题标题】:RestKit complex and simple JSON RKObjectMapping almost working, butRestKit 复杂和简单的 JSON RKObjectMapping 几乎可以工作,但是
【发布时间】:2014-05-07 22:20:12
【问题描述】:

我一直在研究这个问题。以下是一些有助于在 RestKit 中映射此 JSON 响应的发现

JSON 响应对象包含三个顶级对象: 位置是一个数组 cityKey 对象
stateKey 对象

Since Restkit is written in Objective-C, I looked at it as if I were going to directing 映射这些对象并解析出数据

我编写了以下代码来映射 Location Class\Object 的 NSDictionary 部分:

    RKObjectMapping* locationMapping = [RKObjectMapping       mappingForClass:[Location class]];
     [locationMapping addAttributeMappingsFromDictionary:@{
                             @"distance": @"distance",
                             @"major": @"major",
                             @"minor": @"minor" }];

我为整个 class\object , Locations 编写了以下代码: //这也应该是一个 NSDictionary

    RKObjectMapping *locationsMapping = RKObjectMapping       mappingforclass: [Locations class]];

This appears to be a mapping array should be a dictionary.

    [locationsMapping addAttributeMappingsFromArray:@[@"locations", @"cityKey",@"stateKey"]];

我发现在对整个对象位置使用 Array 时出现错误。这将运行并从以下返回部分成功的结果:

RKResponseDescriptor *locationDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:locationMapping method:RKRequestMethodAny pathPattern:@"/location" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [[RKObjectManager sharedManager]    addResponseDescriptor:responseDescriptor];
    [[RKObjectManager sharedManager]    addResponseDescriptor:locationDescriptor];



[[RKObjectManager sharedManager] postObject:nil path:(_enterLocation) parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
     NSLog(@"It Worked: %@", [mappingResult array]);


} failure:^(RKObjectRequestOperation *operation, NSError *error) {
     NSLog(@"It Failed: %@", error);

  }];

This returns the successful responseJSONdata, but mappingResult dictionary returns:

2014-05-07 17:28:39.770 MyApp[163:60b] It Worked: {
    locations =  (
    );

}

The actual JSONOBJECTWITHDATA returned as response.body is:

response.body={
  "locations": [
    {
      "distance": 0.5, 
      "major": 2, 
      "minor": 4, 
      
    }, 
    {
      "distance": 1.0, 
      "major": 2, 
      "minor": 11, 
      
    }
  ], 
  "cityKey": "12", 
  "stateKey": "41"
}

从阅读中,

Will RestKit's dynamic mapping solve this complex JSON mapping?

Feeding parsed data to RKMapperOperation throws NSUnknownKeyException

我知道我需要改变我的 RestKit 映射方法。对于复杂的情况

即使在简单的情况下,我也只是返回一个指向对象的指针。

 RKObjectMapping *statusResponseMapping = [RKObjectMapping mappingForClass:[StatusResponse class]];

    [statusResponseMapping addAttributeMappingsFromDictionary:@{@"status":@"status"}]; 

RKResponseDescriptor *statusResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:statusResponseMapping method:RKRequestMethodPOST pathPattern:nil keyPath:@"response" statusCodes:statusCodes];

我从服务器收到正确的响应...但只得到一个指针

 response.body={
      "response": {
        "status": "ok"
      }
    }
    2014-05-07 17:11:47.362 MyApp[145:60b] It Worked: {
        response = "<StatusResponse: 0x16ee2e10>";

    }

我缺少关键步骤或映射定义。我几乎达到了预期的效果。

我需要做什么才能在简单和复杂的情况下都获得预期的结果?

用下面的新信息更新了我的问题

2014 年 5 月 8 日今天更新,我将位置映射代码更改为...

RKObjectMapping *locationsMapping = [RKObjectMapping mappingForClass:[Locations class]];
    [locationsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations" toKeyPath:@"locations" withMapping:locationMapping]];

这使它更接近正确映射。结果是……

2014-05-08 13:28:17.795 MyApp[165:60b] It Worked: {
    locations =     (
        "<Locations: 0x14e69a10>",
        "<Locations: 0x14e695c0>"
    );

这几乎是正确的。我似乎缺少 cityKey 和 StateKey 的映射。我还没有定义 Description 方法。这是返回的原始 JSON 数据...

response.body={
  "locations": [
    {
      "distance": 0.6, 
      "major": 2, 
      "minor": 4 

    }, 
    {
      "distance": 1.0, 
      "major": 2, 
      "minor": 11 

    }
  ], 
  "cityKey": "11", 
  "stateKey": "21"
}

映射不返回 cityKey 和 stateKey...映射定义中仍然缺少某些内容?

按照建议更改位置映射后于 2014 年 5 月 9 日更新

RKObjectMapping *locationsMapping = [RKObjectMapping mappingForClass:[Locations class]];

    [locationsMapping addAttributeMappingsFromArray:@[
 @"cityKey",@"stateKey"]];

    [locationsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations" toKeyPath:@"locations" withMapping:locationMapping]];


response.body={
  "locations": [
    {
      "distance": 0.6, 
      "major": 2, 
      "minor": 4
    }, 
    {
      "distance": 1.0, 
      "major": 2, 
      "minor": 11
    }
  ], 
  "cityKey": "10", 
  "stateKey": "15"
}
2014-05-09 13:18:17.669 MyApp[211:60b] It Worked: {
    locations  =     (
        "<Locations: 0x1780341e0>",
        "<Locations: 0x170027c40>"
    );
}

仍然缺少 cityKey 和 stateKey...不确定接下来要尝试什么?

于 2014 年 5 月 12 日更新以解决响应描述符...

我有两个响应描述符。我错过了在原始描述中发布一个。

RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:locationMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"locations"  statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
    RKResponseDescriptor *locationDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:locationsMapping method:RKRequestMethodAny pathPattern:@"/location" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
    
    [[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
    [[RKObjectManager sharedManager] addResponseDescriptor:locationDescriptor];

我按照建议更改了结构,但仍然缺少 cityKey 和 stateKey...我应该只使用一个响应描述符吗?

我找到了“使用多个 ResponseDescriptor?”的答案。在本文中http://www.softwarepassion.com/parsing-complex-json-with-objective-c-and-restkit/

当我查看作者如何定义他的 POJO 时,我发现只需要一个 ResponseDescriptor。其余的在关系的映射和定义中处理......

2014 年 5 月 15 日更新

我测试了响应描述符。只有一个人实际上正在努力产生“它有效”的结果。 locationDescriptor 根本不起作用。单独使用时会产生错误。当用作该对的一部分时,它被忽略了。与位置数据一致地传递“It works”的描述符是 responseDescriptor,其 keyPath 为 @"locations"。

我读过http://blog.mobilejazz.cat/ios-using-kvc-to-parse-json/

我有一个关于“...是您创建但没有描述方法实现的自定义类的预期日志输出”的问题。描述方法实现是什么意思?我需要添加什么才能将以下内容更改为映射结果的 NSArray 或 NSDictionary?您能否根据以下位置分享一个示例?

2014-05-09 13:18:17.669 MyApp[211:60b] It Worked: {
        locations  =     (
            "<Locations: 0x1780341e0>",
            "<Locations: 0x170027c40>"
        );

2014 年 5 月 16 日更新,向类实现文件添加了建议的 NSSTRING 描述

response.body={
  "response": {
    "status": "ok"
  }
}
2014-05-16 10:32:26.260 MyApp[202:60b] It Worked: {
    response = "status: ok";
}

因此,我计算了 NSString 描述方法实现已回答并正常工作。

更新的第二部分是使用方法描述符,我可以看到我没有将映射的 JSON 转换为数据结构值,而是我得到了 NULL

response.body={
  "locations": [
    {
      "distance": 0.0, 
      "major": 2, 
      "minor": 8, 

    }, 
    {
      "distance": 3.5, 
      "major": 2, 
      "minor": 9, 

    }, 
    {
      "distance": 2.6575364531836625, 
      "major": 2, 
      "minor": 10, 

    }
  ], 
  "cityKey": "10", 

  "stateKey": "21"
}
2014-05-16 09:48:08.328 MyApp[189:60b] It Worked: {
    locations =     (
        "location: (null) city: (null) state: (null)",
        "location: (null) city: (null) state: (null)",
        "location: (null) city: (null) state: (null)"
    );
}

第一个问题是我应该为字典数组中的三个位置以及一个 cityKey 和一个 stateKey 获取位置 { distance, major, minor}。这是映射代码

RKObjectMapping* locationMapping = [RKObjectMapping mappingForClass:[Location class]];
    [locationMapping addAttributeMappingsFromDictionary:@{
                                                        @"distance": @"distance",
                                                        @"major": @"major",
                                                        @"minor": @"minor"
                                                        }];


    RKObjectMapping *locationsMapping = [RKObjectMapping mappingForClass:[Locations class]];

    [locationsMapping addAttributeMappingsFromArray:@[ @"cityKey",@"stateKey"]];



    [locationsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations" toKeyPath:@"locations" withMapping:locationMapping]];

 //05/16/2014 this ResponseDesciptor is working
   RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:locationsMapping method:RKRequestMethodAny pathPattern:nil keyPath:@"locations" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];

    [[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];

为什么它会为每个位置返回多个 cityKey 和 stateKey?为什么 JSON 数据返回时结果显示为 null?

2014 年 5 月 19 日更新 keyPath 设置为 nil 而不是 @"locations" 时抛出异常

2014-05-19 10:53:53.902 MyApp[245:4907] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<Locations 0x17022d960> valueForUndefinedKey:]: this class is not key value coding-compliant for the key locations.'
*** First throw call stack:

代码提升它 RestKit 代码行 364

if ([self.dataSource respondsToSelector:@selector(mappingOperationShouldSetUnchangedValues:)] && [self.dataSource mappingOperationShouldSetUnchangedValues:self]) return YES;

    id currentValue = [self.destinationObject valueForKeyPath:keyPath];
    if (currentValue == [NSNull null]) {
        currentValue = nil;
    }

Locations 类头文件

#import <Foundation/Foundation.h>

@class Location;


@interface Locations : NSObject




@property (nonatomic, copy) Location *location;
@property (nonatomic, copy) NSString *cityKey;
@property (nonatomic, copy) NSString *stateKey;


@end

位置类实现文件

#import "Locations.h"

@implementation Locations

-(NSString *)description {

    return [NSString stringWithFormat:@"location: %@ cityKey: %@ stateKey: %@", self.location, self.cityKey, self.stateKey];
}

@end   

更改位置类属性来自

@property (nonatomic, copy) Location *location; 

@property (nonatomic, copy) NSMutableArray *locations;

当 keyPath 为 nil 时收到期望的结果

response.body={
  "locations": [
    {
      "distance": 0.0, 
      "major": 2, 
      "minor": 8 

    }, 
    {
      "distance": 3.5, 
      "major": 2, 
      "minor": 9 

    }, 
    {
      "distance": 2.6575364531836625, 
      "major": 2, 
      "minor": 10 

    }
  ], 
  "cityKey": "1", 

  "stateKey": "1"
}
2014-05-19 14:19:45.040 MyApp[290:60b] It Worked: {
    "<null>" = "location: (\n    \"distance: 0 major: 2  minor: 8 \",\n    \"distance: 3.5 major: 2  minor: 9 \",\n    \"distance: 2.657536453183662 major: 2  minor: 10 \"\n) cityKey: 1 stateKey: 1";
}

解决了这个问题。

【问题讨论】:

  • @Wain 在您的帮助下,我更接近于映射 JSON 响应数据。我缺少映射中的第二个、cityKey 和第三个、stateKey、顶级 JSON 对象。我还需要创建一个描述方法实现。请查看并让我知道您的想法。谢谢
  • @Wain 我按照建议更改了位置映射。我收到了没有 cityKey 和 stateKey 的相同位置。不知道接下来要尝试什么...我发布了代码以便您查看。谢谢
  • @Wain 在原始发布中,我错过了发布我的两个 ResponseDescriptor 之一。我更新了帖子以反映两个响应描述符和您的建议。我仍然缺少 cityKey 和 stateKey。我应该只使用一个 ResponseDescriptor 吗?
  • @Wain 我在我的问题中添加了这个发现的参考softwarepassion.com/…...我正在查看 ResKit 对象映射 wiki、此博客帖子和您的建议...我将发布我的结果
  • 我不知道您是否应该有 2 个响应描述符,因为它们具有不同的路径模式。我希望位置映射应该有一个 nil 键路径,我会删除另一个响应描述符,直到你让第一部分工作

标签: ios objective-c json restkit restkit-0.20


【解决方案1】:

当您创建locationsMapping 时,应将@"locations" 添加为使用locationMapping 的关系(而不是直接作为属性)。

您应该有一个使用locationsMapping 的响应描述符。

这个:

2014-05-07 17:11:47.362 MyApp[145:60b] It Worked: {
    response = "<StatusResponse: 0x16ee2e10>";
}

是您创建但没有description 方法实现的自定义类的预期日志输出。


RKObjectMapping *locationsMapping = [RKObjectMapping mappingForClass:[Locations class]];
[locationsMapping addAttributeMappingsFromArray:@[@"cityKey", @"stateKey"]];
[locationsMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"locations" toKeyPath:@"locations" withMapping:locationMapping]];

在您的Locations 班级添加:

- (NSString *)description
{
    return [NSString stringWithFormat:@"city:%@ state:%@ locations:%@", self.cityKey, self.stateKey, self.locations];
}

Location类的类似方法。

【讨论】:

  • 感谢您的帮助。我实施您的建议并发布我的结果。感谢您的快速回复。
  • 您不应该删除其他映射,只需将位置更改为关系映射...
  • 我还没有掌握如何在不删除原始位置映射的情况下将位置更改为关系映射。例如,
  • addAttributeMappingsFromArray:addPropertyMapping:[RKRelationshipMapping... 不互斥。使用两者为您感兴趣的所有不同键添加普通属性映射和关系映射
  • 我会同时使用这两种方法。我会回复你的结果。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-11
  • 2017-06-06
  • 1970-01-01
  • 2011-12-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多