【问题标题】:Strange "mutating method sent to immutable object" error when adding an object to a mutable array将对象添加到可变数组时出现奇怪的“发送到不可变对象的变异方法”错误
【发布时间】:2012-04-18 07:45:14
【问题描述】:

这是一个奇怪的...

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

- (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"];

...行。

对象是可变的。或者至少是这样。为什么会发生变化?

任何帮助的建议将不胜感激。

谢谢。

【问题讨论】:

    标签: objective-c automatic-ref-counting


    【解决方案1】:
    [[[mutableBoardsAndScores objectAtIndex:gameBoardIndex] mutableCopy] setObject:topscoreString forKey:@"topscore"];
    

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

    编辑

    你能把上面的改成:

    NSMutableArray *gameBoard = [[mutableBoardsAndScores objectAtIndex:gameBoardIndex] mutableCopy];
    
    [gameBoard setObject:topscoreString forKey:@"topscore"];
    
    [mutableBoardsAndScores removeObjectAtIndex:gameBoardIndex];
    [mutableBoardsAndScores insertObject:gameBoard atIndex:gameBoardIndex];
    

    你能试试这个吗?这可能不是最漂亮的解决方案,但我相信它会起作用。

    【讨论】:

    • 它不再出错,但它也停止更新 NSUserDefaults。
    【解决方案2】:

    NSUserDefaults 不存储您为其设置的对象。它存储数据。实际上,它正在复制。您从NSUserDefaults 检索到的任何集合对象都将是不可变的。

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

    如果您需要对与属性列表兼容的对象层次结构进行深层复制,以获取可变对象,您可以使用NSPropertyListSerialization。将+dataWithPropertyList:format:options:error: 与+propertyListWithData:options:format:error: 和NSPropertyListMutableContainers 或NSPropertyListMutableContainersAndLeaves 选项结合使用。

    【讨论】:

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