我正在使用rest kit 0.20.3进行一些项目,现在没有问题。 现在我面临的问题是JSON密钥导致“@”导致Restkit在映射数据时崩溃。
JSON看起来像这样:
{
"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"
}
]
}
}
使用
映射应用程序崩溃*** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFDictionary 0x95b5360> valueForUndefinedKey:]: this class is not key value coding-compliant for the key hasChildren.'
因为它试图在字典上调用hasChildren。我的映射看起来像这样:
[mapping addAttributeMappingsFromDictionary:@{
@"id" : @"categoryId",
@"name" : @"name",
@"@hasChildren" : @"doesHaveChildren",
@"@count" : @"numbersOfJobs",
@"trackingName" : @"trackingString"
}];
我已经尝试应用我自己的映射,但遗憾的是它没有用。 是否在RestKit中不支持@我已经使用NSJSONSerialization解析了JSON,它运行良好,但我真的很喜欢RestKit的映射功能,并希望避免编写自己的映射:)
答案 0 :(得分:0)
Key-Value Coding中使用了@
:
集合运算符是作为参数传递给
valueForKeyPath:
方法的专用键路径。运算符由前面带有at符号(@
)的字符串指定。
我不知道告诉NSDictionary
忽略它的方法。您可以在服务器端删除JSON中的@
,也可以在收到它之后但在将其交给RestKit的映射器之前删除。
答案 1 :(得分:0)
这个想法是,例如使用新密钥重新构建字典,新密钥不会包含任何@
个字符。这就是在<{1}}中读取值的方法,其中包含NSDictionary
个字符。
我只需将顶部@
的{{1}}替换为新词典的顶级@
:
_
注意:这只是一个仅在我的代码中处于顶层的概念构思,您可以使用它来创建递归算法来替换更深层次。
答案 2 :(得分:0)
如果您无法更换删除@的密钥,则可以使用另一种方法进行测试
它可能有点激烈,但您可以尝试子类化NSDictionary来替换-(id)valueForKeyPath:(NSString *)keyPath
方法的实现。
我说它很激烈,因为继承类集群(如NSDictionary
)并不容易,你必须做很多测试才能确保RestKit不会抱怨这个。
此外,如果RestKit在一个&#34; custom&#34;中复制字典,这将不会起作用。方式(例如,从零开始构建一个全新的NSDictionary,而不是在我们的自定义子类上使用副本)。
目标是拥有一个实现类似
的方法的子类-(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
的值(如果键是&#34; @ hasChildren&#34;例如)
这会给你这个结果:
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(类集群),您必须覆盖这些方法:
-(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:
方法。
这是一个完整的工作示例:
//
// FLDictionary.m
// Swift123
//
// Created by Lombardo on 18/06/14.
// Copyright (c) 2014 Lombardo. All rights reserved.
//
@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
答案 3 :(得分:0)
感谢您的贡献。在摆动了几个小时后,我跟着@holey和@LombaX建议来取代结果。一个简单而精彩的方法!
我最后通过简单地调用替换即<。p>来替换收到的JSON
NSString *responseStringer = operation.HTTPRequestOperation.responseString;
responseStringer = [responseStringer stringByReplacingOccurrencesOfString:@"\"@" withString:@"\""];
NSData *data = [responseStringer dataUsingEncoding:NSUTF8StringEncoding];
NSError* error;
id parsedData = [RKMIMETypeSerialization objectFromData:data MIMEType:@"application/json" error:&error];
将结果(parsedData)再次传递给RestKit进行映射:
NSDictionary *mappingsDictionary = @{ @"jobCategories.category": MY_RKObjectMapping_MAPPING_OBJECT };
RKMapperOperation *mapper = [[RKMapperOperation alloc] initWithRepresentation:parsedData mappingsDictionary:mappingsDictionary];
NSError *mappingError = nil;
BOOL isMapped = [mapper execute:&mappingError];
if (isMapped && !mappingError) { ... }
非常感谢你的帮助,并指出了我正确的方向!