【问题标题】:'-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object''-[__NSCFDictionary setObject:forKey:]: 变异方法发送到不可变对象'
【发布时间】:2012-09-12 14:13:13
【问题描述】:
- (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 的对象,这样只有那些部分被替换,然后我不必对参数做任何事情,但如果它现在是不可变的,那将是什么时候我尝试再次写信给它。这对我没有任何好处。

【问题讨论】:

  • 最好同时记录 oldTemplates 和 parameters 以查看运行时认为它们是什么类型。 (错误是否给出了对象地址?如果是,它是否与您在此代码中使用的字典之一匹配?)

标签: objective-c xcode immutability nsmutabledictionary


【解决方案1】:

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

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

【讨论】:

  • 没关系。在其他任何地方,我都可以从 plist 中获得 NSMutableDictionary,我可以正常对其进行变异。 —— Xcode 又冻结了。 -- 如果我尝试在updateTemplates 上调用setObject:forKey:,它会继续运行并且我可以记录该对象。所以更新不是一成不变的。嗯。
【解决方案2】:

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

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

【讨论】:

  • 我确实使用 kNilOptions 运行了 NSJSONSerialization。哎呀。
【解决方案3】:

你可以这样做:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-13
    • 2016-11-17
    • 1970-01-01
    相关资源
    最近更新 更多