为什么(复制,非原子)NSMutableArray属性创建NSArrays?

时间:2013-02-13 15:14:17

标签: ios objective-c nsmutablearray nsarray

我在创建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。任何人都可以解释为什么这是正确的行为?

2 个答案:

答案 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,依此类推)设置该属性将始终存储不可变副本。