我在创建TableView class
时犯了一个错误,并在我定义它时意外地将@property
保留为copy
:
@property (copy, nonatomic) NSMutableArray *words;
我正确地初始化了数组:(注意这是第三次尝试,所以请忽略我不使用mutableCopy和其他更好的方法这样做的事实)
NSArray *fixedWords = @[@"Eeny", @"Meeny", @"Miny", @"Moe", @"Catch", @"A", @"Tiger", @"By", @"His", @"Toe"];
NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = mutWords;
然而,当我后来重新排序数组时,它在removeObjectAtIndex行崩溃了:
id object = [self.words objectAtIndex:fromIndexPath.row];
NSUInteger from = fromIndexPath.row;
NSUInteger to = toIndexPath.row;
[self.words removeObjectAtIndex:from];
显示错误消息
unrecognized selector sent to instance
进行了大量挖掘,以确定这是因为复制意味着分配NSMutableArray会导致创建标准(不可变)NSArray。任何人都可以解释为什么这是正确的行为?
答案 0 :(得分:34)
-copy,由可变的Cocoa类实现,总是returns their immutable counterparts。因此,当发送NSMutableArray -copy时,它返回一个包含相同对象的NSArray。
由于words
具有内存限定符copy
,因此该行:
NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = mutWords;
扩展为:
NSMutableArray *mutWords = [[NSMutableArray alloc] initWithArray:fixedWords];
self.words = [mutWords copy];
鉴于NSMutableArray是NSArray的子类,编译器不会抱怨,你现在手上有定时炸弹,因为NSArray不会识别它的可变子类'方法(因为它不能改变它的内容)。 / p>
答案 1 :(得分:8)
属性并不神奇,它们只是简写。在对象上声明@property
告诉编译器为它创建一个支持实例变量和访问器方法。实际生成的代码取决于您在属性上设置的属性。
重要的是要记住,使用点语法设置属性也是简写。当你打电话......
self.words = mutWords;
...你实际上是在幕后调用生成的访问器方法,如下所示:
[self setWords:mutWords];
由于您在属性上指定了copy
属性,因此您已告诉编译器生成-setWords:
访问器方法,其代码如下所示:
- (void)setWords:(NSMutableArray *)words
{
_words = [words copy];
}
了解所有这些,您可以看到发生了什么:生成的setter方法将在输入参数上调用-copy
,并将结果分配给后备实例变量。因为-copy
方法总是被实现为返回不可变对象(执行[aMutableString copy]
将返回NSString,依此类推)设置该属性将始终存储不可变副本。