将对象添加到可变数组时,奇怪的“变异方法发送到不可变对象”错误

时间:2012-04-18 07:45:15

标签: objective-c automatic-ref-counting

这是一个奇怪的......

我正在检查用户是否在我的应用中获得了新的最高分。这是我的代码:

- (void) newTopScore
{
    // pull old top score from the database
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSDictionary *getBoardsAndScores = [defaults dictionaryRepresentation];
    NSMutableArray *boardsAndScores = [[getBoardsAndScores objectForKey:@"boardsAndScores"] mutableCopy];
    NSMutableDictionary *boardAndScoreObject = [[boardsAndScores objectAtIndex:gameBoardIndex] mutableCopy];
    NSString *topscore = [boardAndScoreObject objectForKey:@"topscore"];  

    NSLog(@"topscore in value: %i", [topscore intValue]);

    if ([topscore intValue] == 0)
    {
        NSString *topscoreString = [[NSString alloc] initWithFormat:@"%i", [self countCurrentPegs]];

        NSMutableArray *mutableBoardsAndScores = [boardsAndScores mutableCopy];

        [[mutableBoardsAndScores objectAtIndex:gameBoardIndex] setObject:topscoreString forKey:@"topscore"];

        [defaults setObject:mutableBoardsAndScores forKey:@"boardsAndScores"];
        [defaults synchronize];

    }

    else if ([self countCurrentPegs] < [topscore intValue])
    {
        NSString *topscoreString = [[NSString alloc] initWithFormat:@"%i", [self countCurrentPegs]];

        NSMutableArray *mutableBoardsAndScores = [boardsAndScores mutableCopy];

        [[mutableBoardsAndScores objectAtIndex:gameBoardIndex] setObject:topscoreString forKey:@"topscore"];

        [defaults setObject:mutableBoardsAndScores forKey:@"boardsAndScores"];
        [defaults synchronize];
    }

}

有时代码工作得很好,无论是if还是else。有时虽然我收到以下错误:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '-[__NSCFDictionary setObject:forKey:]: 
mutating method sent to immutable object'

我已尝试设置断点并逐行逐步执行程序。崩溃似乎有点随机,我无法解决模式。它经常在第二次崩溃......

[[mutableBoardsAndScores objectAtIndex:gameBoardIndex] setObject:topscoreString forKey:@"topscore"];

...线。

对象是可变的。或者至少它是。为什么会改变?

非常感谢任何建议的帮助。

感谢。

2 个答案:

答案 0 :(得分:4)

[[[mutableBoardsAndScores objectAtIndex:gameBoardIndex] mutableCopy] setObject:topscoreString forKey:@"topscore"];

你能测试一下吗? (为gameBoard添加了mutableCopy);

修改

你可以将上面改为:

NSMutableArray *gameBoard = [[mutableBoardsAndScores objectAtIndex:gameBoardIndex] mutableCopy];

[gameBoard setObject:topscoreString forKey:@"topscore"];

[mutableBoardsAndScores removeObjectAtIndex:gameBoardIndex];
[mutableBoardsAndScores insertObject:gameBoard atIndex:gameBoardIndex];
你可以尝试一下吗?它可能不是最美丽的解决方案,但我相信它会起作用。

答案 1 :(得分:1)

NSUserDefaults不会存储您为其设置的对象。它存储数据。实际上,它正在制作副本。 <{1}}中检索的任何集合对象都是不可变的。

编辑说:另外,当你制作一个可变的集合副本时,它是一个浅层副本。您获得一个可变集合,其中包含与原始集合相同的对象。如果原始集合持有不可变对象,那么新集合也将如此。

如果需要对属性列表兼容的对象层次结构进行深层复制,将可变对象恢复,则可以使用NSUserDefaults。将NSPropertyListSerialization+dataWithPropertyList:format:options:error:+propertyListWithData:options:format:error:NSPropertyListMutableContainers选项合并。