' - [__ NSCFDictionary setObject:forKey:]:发送到不可变对象的mutating方法'

时间:2012-09-12 14:13:13

标签: objective-c xcode immutability nsmutabledictionary

- (NSMutableDictionary *)updateTemplates:(NSMutableDictionary *)oldTemplates
                             forSpecType:(NSString *)specType {
    // oldTemplates is an NSMutableDictionary pulled from a plist
    // specType is used for flexible paths, to eliminate duplicate code

    // Make a dict of the parameters object (about to be overwritten)
    NSMutableDictionary *parameters = [oldTemplates valueForKeyPath:
                  [NSString stringWithFormat:@"root.%@.parameters", specType]];

    // Dump the new data into the matching object
    [oldTemplates setValue:[updateTemplates valueForKeyPath:
                              [NSString stringWithFormat:@"data.%@", specType]]
                forKeyPath:[NSString stringWithFormat:@"root.%@", specType]];

    // Put the parameters back, since they don't exist anymore
    /* Instant crash, with the debugger claiming something is immutable
     * But I just used the exact same method on the line above
     * updateTemplates isn't immutable either; it's only when I try to mutate
       oldTemplates after putting in updateTemplates -- and only the update
       seems to be breaking things -- that I get the exception and crash
    */
    [oldTemplates setValue:parameters forKeyPath:
                  [NSString stringWithFormat:@"root.%@.parameters", specType]];

    return oldTemplates;
}

我可以设置一个循环来一次写一个updateTemplates.specType的对象,这样只有那些部分被替换,然后我不需要对参数做任何事情,但是如果它现在是不可变的,它将会当我再次尝试写信时。那对我没有任何帮助。

3 个答案:

答案 0 :(得分:4)

如果我没记错的话,默认情况下,从plist或NSUserDefaults创建的词典是不可变的。您必须手动创建可变副本:

NSMutableDictionary *parameters = [[oldTemplates valueForKeyPath:
           [NSString stringWithFormat:@"root.%@.parameters", specType]] mutableCopy];

答案 1 :(得分:3)

mutableCopy制作一个浅的可变副本,而不是一个深度可变副本。如果您的NSDictionary包含值为NSDictionary个实例的键/值对,mutableCopy将返回一个包含NSDictionary个不可变实例的可变字典作为值。

您需要执行深层复制或使用plist序列化功能来解码启用了mutable collections选项的plist。或者你可以编写一个从旧版本派生的新集合。

答案 2 :(得分:0)

您可以这样做:

NSMutableDictionary* oldTemplates = [NSMutableDictionary dictionaryWithDictionary:[oldTemplates valueForKeyPath:
                  [NSString stringWithFormat:@"root.%@.parameters", specType]]];

这将从现有的NSDictionary

创建一个可变副本