是否有人对未知结构的NSDictionary进行了递归有序遍历?我想采用任何NSDictionary并按层次顺序处理每个级别。
1)此数据来自经过验证的JSON。可以肯定地说,从SBJSON(JSON Framework)这样的框架创建的NSDictionary只会导致嵌套字典,数组和任意叶子的组合吗?
2)如何使用适用于数组和字典的快速枚举来完成泛型遍历?使用下面的代码,一旦我到达数组中的字典,它就会停止遍历。但是,如果我继续数组条件中的递归(以检查数组中的字典),它会在id value = [dict valueForKey:key];
的下一次迭代中使用-[__NSCFDictionary length]: unrecognized selector sent to instance
SIGABRT进行barfs。我不知道为什么这会成为一个问题,因为我已经通过一个顶级字典(其中找到了子级字典数组)超过了该行。
-(void)processParsedObject:(id)dict counter:(int)i parent:(NSString *)parent
{
for (id key in dict) {
id value = [dict valueForKey:key];
NSLog(@"%i : %@ : %@ -> %@", i, [value class], parent, key);
if ([value isKindOfClass:[NSDictionary class]])
{
i++;
NSDictionary* newDict = (NSDictionary*)value;
[self processParsedObject:newDict counter:i parent:(NSString*)key];
i--;
}
else if ([value isKindOfClass:[NSArray class]])
{
for (id obj in value) {
NSLog(@"Obj Type: %@", [obj class]);
}
}
}
}
非常感谢
答案 0 :(得分:31)
我做了类似的事情,我将遍历来自Web服务的JSON结构化对象,并将每个元素转换为可变版本。
- (void)processParsedObject:(id)object
{
[self processParsedObject:object depth:0 parent:nil];
}
- (void)processParsedObject:(id)object depth:(int)depth parent:(id)parent
{
if ([object isKindOfClass:[NSDictionary class]])
{
for (NSString* key in [object allKeys])
{
id child = [object objectForKey:key];
[self processParsedObject:child depth:(depth + 1) parent:object];
}
}
else if ([object isKindOfClass:[NSArray class]])
{
for (id child in object)
{
[self processParsedObject:child depth:(depth + 1) parent:object];
}
}
else
{
// This object is not a container you might be interested in it's value
NSLog(@"Node: %@ depth: %d", [object description], depth);
}
}
答案 1 :(得分:4)
我需要知道这些值的关键名称,所以我重新写了Joel的内容并想出了这个:
- (void)enumerateJSONToFindKeys:(id)object forKeyNamed:(NSString *)keyName
{
if ([object isKindOfClass:[NSDictionary class]])
{
// If it's a dictionary, enumerate it and pass in each key value to check
[object enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL *stop) {
[self enumerateJSONToFindKeys:value forKeyNamed:key];
}];
}
else if ([object isKindOfClass:[NSArray class]])
{
// If it's an array, pass in the objects of the array to check
[object enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
[self enumerateJSONToFindKeys:obj forKeyNamed:nil];
}];
}
else
{
// If we got here (i.e. it's not a dictionary or array) so its a key/value that we needed
NSLog(@"We found key %@ with value %@", keyName, object);
}
}
然后你会这样称呼:
[self enumerateJSONToFindKeys:JSON forKeyNamed:nil];
或者,如果您想使给定的密钥路径可变(因此您可以使用setValue:forKeyPath:
回写它),您可以执行以下操作:
- (void)makeDictionariesMutableForKeyPath:(NSString *)keyPath {
NSArray *keys = [keyPath componentsSeparatedByString:@"."];
NSString *currentKeyPath = nil;
for (NSString *key in keys) {
if (currentKeyPath) {
NSString *nextKeyPathAddition = [NSString stringWithFormat:@".%@", key];
currentKeyPath = [currentKeyPath stringByAppendingString:nextKeyPathAddition];
} else {
currentKeyPath = key;
}
id value = [self.mutableDictionary valueForKeyPath:currentKeyPath];
if ([value isKindOfClass:NSDictionary.class]) {
NSMutableDictionary *mutableCopy = [(NSDictionary *)value mutableCopy];
[self.mutableDictionary setValue:mutableCopy forKeyPath:currentKeyPath];
}
}
}