首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用前面的"@“和restkit映射JSON键

用前面的"@“和restkit映射JSON键
EN

Stack Overflow用户
提问于 2014-06-18 16:21:27
回答 4查看 354关注 0票数 0

我正在与rest工具包0.20.3为一些项目,现在没有问题。现在,我面临的问题是JSON键导致"@“,这会导致Restkit在映射数据时崩溃。

JSON看起来如下所示:

代码语言:javascript
复制
{
    "city": {
        "@name": "Charles Redirection City",
        "@nameUrl": "Charles Redirection City",
        "lat": "52.5238",
        "long": "13.4119",
        "zipCode": "666"
    },
    "categories": {
        "@count": "20037",
        "category": [
            {
                "@count": "2326",
                "@hasChildren": "true",
                "id": "15777",
                "name": "Sticky-Categorie"
            }
        ]
    },
    "additional": {
        "dataKey": [
            {
                "@key": "log-start",
                "$": "home"
            }
        ]
    }
}

在将应用程序映射为

代码语言:javascript
复制
*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFDictionary 0x95b5360> valueForUndefinedKey:]: this class is not key value coding-compliant for the key hasChildren.'

当它试图在字典上调用hasChildren时。我的地图如下所示:

代码语言:javascript
复制
[mapping addAttributeMappingsFromDictionary:@{
                                              @"id"                 :   @"categoryId",
                                              @"name"               :   @"name",
                                              @"@hasChildren"       :   @"doesHaveChildren",
                                              @"@count"             :   @"numbersOfJobs",
                                              @"trackingName"       :   @"trackingString"
                                              }];

我已经尝试了应用我自己的映射,但不幸的是,它没有起作用。在RestKit中是否不支持前导@?我已经用NSJSONSerialization解析了JSON,它工作得很好,但是我非常喜欢RestKit的映射特性,并且希望避免编写自己的映射:)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-06-18 16:30:16

@用于键值编码

集合运算符是作为参数传递给valueForKeyPath:方法的专用密钥路径。运算符由一个字符串指定,前面有一个at符号(@)。

我不知道有什么方法可以让NSDictionary忽略它。您可以从JSON中删除@,无论是在服务器端,还是在收到JSON之后,但在将其交给RestKit的映射程序之前。

票数 0
EN

Stack Overflow用户

发布于 2014-06-18 16:39:31

其想法是,例如,用新键重新构建字典,它将不包含任何@字符。这就是在键中有NSDictionary字符的@中读取值的方法。

我只是将@键替换为顶层的_,用于新字典:

代码语言:javascript
复制
NSDictionary *_dictionary; // your original dictionary
NSMutableDictionary *_validatedDictionary = [NSMutableDictionary dictionary];
[_dictionary enumerateKeysAndObjectsUsingBlock:^(NSString * key, id obj, BOOL *stop) {
    NSString *_validKey = [key stringByReplacingOccurrencesOfString:@"@" withString:@"_"];
    [_validatedDictionary setObject:obj forKey:_validKey];
}];

注意:这只是一个只在我的代码中在顶层工作的概念想法,您可以使用它来创建一个递归算法来取代更深层次的算法。

票数 0
EN

Stack Overflow用户

发布于 2014-06-18 17:32:40

如果无法替换移除@的键,则还有另一种解决方案可供测试。

这可能有点激烈,但您可以尝试将NSDictionary子类替换为-(id)valueForKeyPath:(NSString *)keyPath方法的实现。

我说这很激烈,因为对类集群进行子类化(像NSDictionary这样的子类从来就不容易),您必须做很多测试才能确保RestKit不会抱怨这一点。

此外,如果RestKit以“自定义”的方式复制字典(例如,从零开始构造一个全新的NSDictionary,而不是在我们的自定义子类上使用副本),这是行不通的。

目标是有一个子类来实现这样的方法

代码语言:javascript
复制
-(id)valueForKeyPath:(NSString *)keyPath
{
    if ([[keyPath substringToIndex:1] isEqualToString:@"@"])
    {
        return [_subDictionary objectForKey:keyPath];   // if the first character is @, return the result of objectForKey
    } else {
        return [_subDictionary valueForKeyPath:keyPath];
    }

}

您可以更改方法以返回objectForKey的值,而不是仅在某些情况下才返回valueForKeyPath的值(例如,如果键是"@hasChildren“)。

这将给你这个结果:

代码语言:javascript
复制
self.aDictionary = [[FLDictionary alloc] initWithObjects:@[@"pluto"] forKeys:@[@"@pippo"]];
NSLog(@"Value is %@", [self valueForKeyPath:@"aDictionary.@pippo"]);


NSLog result: 2014-06-18 19:24:34.605 Swift123[25663:454958] Value is pluto

然而,现在出现了困难的部分。为了子类NSDictionary (类集群),您必须重写以下方法:

代码语言:javascript
复制
-(instancetype)initWithObjects:(const id [])objects forKeys:(const id<NSCopying> [])keys count:(NSUInteger)cnt;
-(NSUInteger)count;
-(id)objectForKey:(id)aKey;
-(NSEnumerator *)keyEnumerator;

重写意味着您应该为新创建的字典实现自己的存储。为了避免这种情况,我创建了一个带有底层NSDictionary的实例变量。我将在文章的末尾发布完整的代码。

另外要注意的是:复制NSDictionaries是一种惯例。这将导致您的自定义类在第一个副本时被提交到一个标准的NSDictionary中。因此,您甚至必须对copyWithZone:方法进行子类化。

这里是一个完整的工作示例:

代码语言:javascript
复制
//
//  FLDictionary.m
//  Swift123
//
//  Created by Lombardo on 18/06/14.
//  Copyright (c) 2014 Lombardo. All rights reserved.
//

进口"FLDictionary.h“

代码语言:javascript
复制
@interface FLDictionary ()

@property (copy, nonatomic) NSDictionary *subDictionary;

@end

@implementation FLDictionary


-(instancetype)initWithObjects:(const id [])objects forKeys:(const id<NSCopying> [])keys count:(NSUInteger)cnt
{
    self = [self init];
    if (self) {
        _subDictionary = [[NSDictionary alloc] initWithObjects:objects forKeys:keys count:cnt];
    }
    return self;
}

-(NSUInteger)count
{
    return [_subDictionary count];
}

-(id)objectForKey:(id)aKey
{
    return [_subDictionary objectForKey:aKey];
}

-(NSEnumerator *)keyEnumerator
{
    return [_subDictionary keyEnumerator];
}

-(id)valueForKeyPath:(NSString *)keyPath
{
    if ([[keyPath substringToIndex:1] isEqualToString:@"@"])
    {
        return [_subDictionary objectForKey:keyPath];
    } else {
        return [_subDictionary valueForKeyPath:keyPath];
    }

}



-(id)copyWithZone:(NSZone *)zone
{
    id objects[ [_subDictionary count] ];
    id keys[ [_subDictionary count] ];

    int i = 0;
    for (id item in [_subDictionary allValues])
    {
        objects[i++] = item;
    }

    i = 0;
    for (id item in [_subDictionary allKeys])
    {
        keys[i++] = item;
    }

    FLDictionary *dict = [[[self class] allocWithZone:zone] initWithObjects:objects forKeys:keys count:[_subDictionary count]];
    return dict;

}

@end
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/24290577

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档