为什么(复制,非primefaces)的NSMutableArray属性创buildNSArrays?

我在创build一个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; 

但是,当我后来对数组重新sorting时,它在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导致创build标准(不可变的)NSArray。 任何人都可以解释为什么这是正确的行为?

-copy,由可变的Cocoa类实现,总是返回它们的不可变对象 。 因此,当发送一个NSMutableArray时,它将返回一个包含相同对象的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不识别它的可变子类的方法(因为它不能改变它的内容)。

属性并不神奇,它们只是速记。 在你的对象上声明@property告诉编译器为它创build一个支持的实例variables和访问器方法。 实际生成的代码取决于您在属性上设置的属性。

记住使用点语法来设置一个属性也是很重要的。 你打电话时…

 self.words = mutWords; 

…实际上在幕后调用生成的访问器方法,如下所示:

 [self setWords:mutWords]; 

由于您在属性上指定了copy属性,因此您已经告诉编译器生成-setWords: accessor方法,其代码如下所示:

 - (void)setWords:(NSMutableArray *)words { _words = [words copy]; } 

知道所有这一切,你可以看到发生了什么事情:生成的setter方法将在input参数上调用-copy ,并将结果分配给支持的实例variables。 因为-copy方法总是被实现来返回一个非可变对象(执行[aMutableString copy]将返回一个NSString,等等)设置该属性将始终存储一个不可变的副本。