所以我有一个属性NSMutableArray *grades
。在我设置此属性的唯一地方,我这样做:
NSMutableArray *array = [[NSMutableArray alloc] init];
self.grades = array;
[array release];
[self.grades addObject:@"20"];
最后一个语句会生成异常:-[NSCFArray insertObject:atIndex:]: mutating method sent to immutable object'
。
我错过了什么?
答案 0 :(得分:8)
听起来该属性设置为copy
,这意味着合成访问器会生成数组的不可变副本
答案 1 :(得分:6)
确保grades
是NSMutableArray
。
编辑:
copy
返回不可变副本,因此您无法进行更改。来自Apple的Objective-C docs:
如果使用复制声明属性,则指定在分配期间复制值。如果合成相应的访问器,则合成方法使用复制方法。这对于诸如字符串对象之类的属性很有用,在这些属性中,setter中传递的新值可能是可变的(例如,NSMutableString的一个实例),并且您希望确保您的对象具有自己的私有不可变副本。例如,如果您声明属性如下:
虽然这适用于字符串,但如果属性是一个集合(如数组或集合),则可能会出现问题。通常,您希望此类集合是可变的,但复制方法返回集合的不可变版本。在这种情况下,您必须提供自己的setter方法实现,如以下示例所示。
在分配时复制整个集合是一项繁重的操作。您确定不想retain
收藏,还是仅assign
收藏?
如果您真的想要一个可变副本,那么请按照文档建议编写您自己的setter。
- (void)setGrades:(NSMutableArray *)array {
// make shallow/deep copy here, and assign to `grades`, not `self.grades`
}
答案 2 :(得分:0)
什么是grades
声明为?
从错误消息的外观中声明grades
作为NSArray,虽然这是有效的,但它确实意味着你失去了数组的可变性。
要将数组维护为可变,您还需要将等级声明为NSMutableArray。
编辑:
根据您的编辑,原因可能是您在属性中使用copy
关键字,这意味着当您使用self.grades
分配数组时,合成的setter方法会生成不可变的副本array
答案 3 :(得分:0)
self.grades可能会返回一个NSArray,如果声明为@property NSArray* grades
,则会看到编译器怪异并且不想支持addObject:
方法。你有2个选择