可变数组中包含可变数组。不可变对象调用了可变方法。

7
我有一个NSMutableArray包含了多个NSMutableArrays:
 NSMutableArray *array = [[NSMutableArray alloc]init];

        for (int i = 0; i < 5; i++)
        {
            NSMutableArray *miniArray = [[NSMutableArray alloc]init];

            for (int k = 0; k < 30; k++)
            {   
                [miniArray addObject:@"0"];
            }
            [array addObject:miniArray];
        }

然后,当我尝试这样做时:
 [[array objectAtIndex:packIndex]replaceObjectAtIndex:index withObject:@"1"];

出现错误: [__NSCFArray replaceObjectAtIndex:withObject:]: mutating method sent to immutable object'

为什么会出现这个错误?如何解决?谢谢!

更新: 我将该数组保存在NSUserDefaults中:

[defaults setObject:array forKey:@"mainArray"];

然后,我在另一个班级里阅读了它:
array = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"mainArray"]];

还有一点需要提到的是,有时代码可以正常运行并将“0”更改为“1”。但有时会崩溃。所以我看不出它为什么能够正常工作或者为什么有时会崩溃。


1
什么是boolArray?你是不是指的是miniArray? - rdelmar
你的问题中有错别字,还是你的代码里有错别字? - rdelmar
@rdelmar 在问题中打错了字。在代码中是正确的。 - SmartTree
1
这段代码应该可以正常工作。你没有展示所有的内容,"packIndex"是什么?在你展示的代码块和替换方法之间发生了什么代码? - Ben Zotto
再次问一下,在您展示的代码片段和抛出异常的那行代码之间发生了什么? - Hermann Klecker
显示剩余3条评论
3个回答

26

问题在于,当您从NSUserDefaults中读取数组时,子数组不会自动转换为NSMutableArrays。

尝试这样做:

array = [[NSMutableArray alloc]initWithArray:[[NSUserDefaults standardUserDefaults] objectForKey:@"mainArray"]];
for(int i = 0; i < array.count; i++) {
    NSArray * tempArray = array[i];
    array[i] = [tempArray mutableCopy];
}

编辑: 最佳编码者的答案解释了这一点。 存储在NSUserDefaults中的对象被存储为不可变版本,基本上NSUserDefaults是一个属性列表(plist),没有标记数组是否可变/不可变的标志,因此当你将它们读回来时,它们被认为是不可变的。


1
我试过了,它非常好用!谢谢。您能否解释一下,为什么小数组如果最初是NSMutaleArrays,它们不会自动转换成NSMutaleArrays? - SmartTree
@SmartTree 从 NSUserDefaults 读取的所有数据都以其不可变形式返回。即使是从 NSUserDefaults 读取的主数组也是不可变的。 - rmaddy
2
只是添加一些更多的信息:NSUserDefaults始终返回不可变集合,但对于属性列表的一般情况,NSPropertyListSerialization有返回可变集合的选项。因此,如果您将数组存储在除NSUserDefaults之外的其他位置,则可以选择该选项。 - Chuck
谢谢,节省了我的时间。同时我也学到了关于可变数组的新东西 :) - mAc

6
从NSUserDefaults返回的值是不可变的,即使您将可变对象设置为值。例如,如果您将可变字符串设置为"MyStringDefault"的值,则稍后使用stringForKey:检索的字符串将是不可变的。
相反,复制您从NSUserDefaults检索的数组并添加您的对象,然后将新数组重新设置回去。
请参阅此链接: https://developer.apple.com/documentation/foundation/nsuserdefaults

-5

尝试使用更详细的代码:

NSMutableArray *tempArray = [array objectAtIndex:packIndex];
[tempArray replaceObjectAtIndex:index withObject:@"1"];

你能解释一下为什么你认为这会有帮助吗?这两者是等价的。 - jscs
由于某些原因,小型数组未被存储为可变数组。这将强制它们成为可变的。 - Chris C
3
这不会强制它们可变。你可能在使用某种语言时遇到过,将一个类型的对象分配给另一种类型的变量会进行类型转换。但在Objective-C中不是这样的。所有的对象变量都是指针,将一个类型的指针分配给另一种类型的指针变量不会改变底层数据——它只是欺骗编译器变量指向的位置。对象类型只是用于静态类型检查,并确保属性使用正确的访问器。 - Chuck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接