xcode '-[__NSCFDictionary setObject:forKey:]:发送到不可变对象的变异方法'

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12390159/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 01:28:13  来源:igfitidea点击:

'-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object'

objective-cxcodeimmutabilitynsmutabledictionary

提问by Thromordyn

- (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;
}

I could set up a loop to write one object of updateTemplates.specTypeat a time so only those parts get replaced and then I don't have to do anything with the parameters, but if it's immutable now, it will be when I try to write to it again. That won't do me any good.

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

回答by Snowman

If I remember correctly, dictionaries created from plists or NSUserDefaults are immutable by default. You'll have to create a mutable copy manually:

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

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

回答by bbum

mutableCopymakes a shallow mutable copy, not a deep mutable copy. If you have an NSDictionarycontaining key/value pairs where the values are NSDictionaryinstances, mutableCopywill return a mutable dictionary containing those NSDictionaryimmutable instances as values.

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

You either need to do a deep copy or use the plist serialization functionality to decode the plist with the mutable collections option enabled. Or you could compose a new collection derived from the old.

您要么需要进行深度复制,要么使用 plist 序列化功能在启用可变集合选项的情况下解码 plist。或者你可以从旧的集合中创建一个新的集合。

回答by jere

You can simply do:

你可以简单地做:

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

This will create a mutable copy from an existing NSDictionary

这将从现有的 NSDictionary 创建一个可变副本