NSDictionary中键的路径

时间:2013-05-03 15:33:48

标签: objective-c cocoa recursion nsdictionary

在我的应用程序中,我需要将值插入到仅具有最后路径组件的NSDictionary中。例如。我的命令是

a = 1;
b = 2;
c = 3;
d =     {
    e = 4;
    f = 5;
    g =         {
        h = 6;
    };
};
j =     {
    k = 7;
};

我需要更改k的值。路径组件应为@[@"j", @"k"]。我尝试了类似的东西:

- (void)recurse:(NSDictionary*)dict keyToFound:(NSString*)ktf stack:(NSMutableArray*)stack parent:(NSString*)parent
{
    for (NSString *key in [dict allKeys]) {
    if ([key isEqualToString:ktf]) {
        [stack insertObject:key atIndex:[stack count]];

        return;
    }
    else {
        if ([[dict valueForKey:key] isKindOfClass:[NSDictionary class]]) {
            NSDictionary *d = [dict valueForKey:key];
            [stack insertObject:key atIndex:[stack count]];
            [self recurse:d keyToFound:ktf stack:stack parent:key];
            //[stack removeObject:key];
        }
    }
}

}

但是,obviuos,这是一种错误的方式。

3 个答案:

答案 0 :(得分:1)

以下是在嵌套字典中设置值的两种更简单的方法。第一个假设您知道密钥存在并且可能是C标识符。在这种情况下,使用setValue:forKeyPath:是最好的方法。否则,函数中的简单循环(或NSDictionary上的方法或类别)将起到作用:

void setValueForPathComponentsOfDictionary(id value, NSArray *components, NSMutableDictionary *dict) {

    NSMutableArray *parts = [components mutableCopy];
    id lastPart = parts.lastObject;
    [parts removeLastObject];

    for (id part in parts) {
        if (![dict respondsToSelector:@selector(objectForKey:)])
            return; // Silently fail.
        dict = [dict objectForKey:part];
    }

    if ([dict respondsToSelector:@selector(objectForKey:)])
        [dict setValue:value forKey:lastPart];
}

int main (int argc, const char * argv[])
{
    @autoreleasepool {

        NSMutableDictionary *dict = [@{
            @"a":[@{@"a":@1,@"b":@2} mutableCopy],
            @"b":[@{@"a":@3,@"b":@4} mutableCopy]
        } mutableCopy];

        NSLog(@"Initial Dictionary: %@", dict);

        [dict setValue:@9 forKeyPath:@"a.b"];
        NSLog(@"After setValue:forKeyPath: %@", dict);

        setValueForPathComponentsOfDictionary(@0, @[@"b",@"a"], dict);
        NSLog(@"After setValueForPathComponentsOfDictionary %@", dict);
    }
    return 0;
}

答案 1 :(得分:0)

好的,我找到了解决方案。

- (BOOL)recurse:(NSDictionary*)dict keyToFound:(NSString*)ktf stack:(NSMutableArray*)stack parent:(NSString*)parent
{
    BOOL result = NO;
    for (NSString *key in [dict allKeys]) {
        if ([key isEqualToString:ktf]) {
            [stack insertObject:key atIndex:[stack count]];
            return YES;
        }
        else {
            if ([[dict valueForKey:key] isKindOfClass:[NSDictionary class]]) {
                NSDictionary *d = [dict valueForKey:key];
                [stack insertObject:key atIndex:[stack count]];
                result = [self recurse:d keyToFound:ktf stack:stack parent:key];
                if (!result) {
                    [stack removeLastObject];
                }
            }
        }
    }
    return result;
}

答案 2 :(得分:0)

NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithObjectsAndKeys:@1,@"a",
                      @1,@"b",
                      @2,@"c",
                      [NSMutableDictionary dictionaryWithObjectsAndKeys:@4, @"e",
                       @5, @"f",
                       [NSMutableDictionary dictionaryWithObject:@6 forKey:@"h"], @"g", nil],@"d",
                      [NSMutableDictionary dictionaryWithObject:@7 forKey:@"k"],@"i",nil];
NSLog(@"Before %@",dict);

NSString *keyToChange = @"e";
NSString *valueToChange = @"Your New Value";

[dict enumerateKeysAndObjectsUsingBlock:^(id key ,id obj, BOOL *stop){
    if([key isEqualToString:keyToChange])
    {
        NSLog(@"Found : %@",keyToChange);
        if(![obj isKindOfClass:[NSArray class]] || ![obj isKindOfClass:[NSDictionary class]] || ![obj isKindOfClass:[NSMutableDictionary class]])
        {
            [dict setValue:@"newval" forKey:keyToChange];
            return;
        }
    }
    if([obj isKindOfClass:[NSDictionary class]])
    {
        [obj enumerateKeysAndObjectsUsingBlock:^(id key ,id obj1, BOOL *stop){
            if([key isEqualToString:keyToChange])
            {
                if(![obj isKindOfClass:[NSArray class]] || ![obj isKindOfClass:[NSDictionary class]] || ![obj isKindOfClass:[NSMutableDictionary class]])
                {
                    NSLog(@"Found : %@",keyToChange);
                    [obj setValue:@"newval" forKey:keyToChange];
                    return;
                }
            }
        }];
    }
}];
NSLog(@"After %@",dict);