valueForKeyPath failing with nested NSMutableDictionary objects

131 Views Asked by At

On my class I have two data objects: 'dataDict' (property) and 'prevDict' (instance variable) which are both NSMutableDictionary objects. In these multi-level dictionaries all the 'nodes' are themselves NSMutableDictionary objects and all the 'leaves' are NSString values.

Most of the time, these dictionaries will compare to be the same. But, when the new incoming data is different, I want to capture those changes via KVO and then save the new incoming dictionary. The recursive calls are the thing that fires off all the KVO changes.

Below is the code for recursively determining if the new incoming data (in property 'dataDict') is different than what's in the 'prevDictionary'. The initial call is:

[self postChangesFromPrevDict:prevDict usingKeyPath:@"dataDict"];
prevDict = [[NSMutableDictionary alloc] initWithDictionary:self.dataDict copyItems:YES];

If there's a change on a given leaf, it should update that in the dictionary and produce a KVO notification.

A sample 'newPath' string value could be "dataDict.group.name.points" -- in which the 'key' value is "points".

In the debugger breakpoint noted, I can see the values of 'curStr' and 'newStr' as, say, "120" and "121" with the these two values being correctly obtained from prevDict and dataDict, respectively.

If I obtain a value from a given keyPath then set it again using that SAME key path, why am I getting an NSUnknownKeyException?

I do know that all my dictionaries involved are mutable.

-(void) postChangesFromPrevDict:(NSMutableDictionary *)prevDictionary
               usingKeyPath:(NSString *)keyPath
{
    NSArray *keys = [prevDictionary allKeys];
    for (NSString *key in keys) {
        id obj = [prevDictionary objectForKey:key];
        NSString *newPath = [keyPath stringByAppendingString:[NSString stringWithFormat:@".%@",key]];
        if ([obj isKindOfClass:[NSDictionary class]])
            [self postChangesFromPrevDict:obj usingKeyPath:newPath];
        else {
            NSString *curStr = obj;
            NSString *newStr = [self valueForKeyPath:newPath];
            //debug breakpoint
            if (![newStr isEqualToString:curStr]) {
                @try {
                    [self setValue:newStr forKeyPath:newPath];
                }
                @catch (NSException *__unused exception) {
                    NSLog(@"Can't set key on %@",newPath);
                }
            }
        }
    }
}

PS: To recurse, I test for an NSDictionary class which is fine as NSMutableDictionary is a subclass thereof.

0

There are 0 best solutions below