复制和mutableCopy如何适用于NSArray和NSMutableArray?

NSArrayNSMutableArray上使用copymutableCopy什么区别?

这是我的理解; 这是对的吗?

 // ** NSArray ** NSArray *myArray_imu = [NSArray arrayWithObjects:@"abc", @"def", nil]; // No copy, increments retain count, result is immutable NSArray *myArray_imuCopy = [myArray_imu copy]; // Copys object, result is mutable NSArray *myArray_imuMuta = [myArray_imu mutableCopy]; // Both must be released later 

 // ** NSMutableArray ** NSMutableArray *myArray_mut = [NSMutableArray arrayWithObjects:@"A", @"B", nil]; // Copys object, result is immutable NSMutableArray *myArray_mutCopy = [myArray_mut copy]; // Copys object, result is mutable NSMutableArray *myArray_mutMuta = [myArray_mut mutableCopy]; // Both must be released later 

copymutableCopy定义在不同的协议(分别NSCopyingNSMutableCopying )和NSArray符合两者。 mutableCopy是为NSArray (而不仅仅是NSMutableArray )定义的,并允许你创build一个原本不可变的数组的可变副本:

 // create an immutable array NSArray *arr = [NSArray arrayWithObjects: @"one", @"two", @"three", nil ]; // create a mutable copy, and mutate it NSMutableArray *mut = [arr mutableCopy]; [mut removeObject: @"one"]; 

概要:

  • 无论原始types如何,您都可以依赖mutableCopy的结果进行修改。 在数组的情况下,结果应该是一个NSMutableArray
  • 不能依靠copy的结果是可变的! copy一个NSMutableArray 可能会返回一个NSMutableArray ,因为这是原始类,但copy任何任意的NSArray实例不会。

编辑:根据Mark Bessey的回答重新阅读你的原始代码。 当你创build你的数组副本时,当然你仍然可以修改原始数据而不pipe你使用的是什么副本。 copy vs mutableCopy会影响新数组是否可变。

编辑2:修正了我(错误)的假设, NSMutableArray -copy将返回一个NSMutableArray

我想你一定误解了copy和mutableCopy是如何工作的。 在您的第一个示例中,myArray_COPY是myArray的不可变副本。 完成复制后,您可以操作原始myArray的内容,而不会影响myArray_COPY的内容。

在第二个示例中,您创build了myArray的可变副本,这意味着您可以修改该数组的副本,而不会影响其他副本。

如果我更改第一个示例以尝试从myArray_COPY插入/删除对象,则会失败,就像您期望的那样。


也许考虑一个典型的用例会有所帮助。 通常情况下,您可能会编写一个采用NSArray *参数的方法,并基本上将其存储以供以后使用。 你可以这样做:

 - (void) doStuffLaterWith: (NSArray *) objects { myObjects=[objects retain]; } 

…但是,那么你有问题,该方法可以用一个NSMutableArray作为参数来调用。 创build该数组的代码可能会在调用doStuffLaterWith:方法之间以及之后需要使用该值时进行操作。 在一个multithreading的应用程序中,甚至可以在迭代时更改数组的内容,这可能会导致一些有趣的错误。

如果你这样做:

 - (void) doStuffLaterWith: (NSArray *) objects { myObjects=[objects copy]; } 

然后该副本在调用该方法时创build数组内容的快照。

“copy”方法返回通过实现NSCopying协议copyWithZone创build的对象:

如果您向NSString发送复制消息:

 NSString* myString; NSString* newString = [myString copy]; 

返回值将是一个NSString(不可变)


mutableCopy方法返回通过实现NSMutableCopying协议的mutableCopyWithZone创build的对象:

通过发送:

 NSString* myString; NSMutableString* newString = [myString mutableCopy]; 

返回值是可变的。


在任何情况下,对象都必须实现协议,表示它将创build新的复制对象并将其返回给您。


在NSArray的情况下,对于浅层和深层复制还有一个额外的复杂程度。

一个NSArray的浅拷贝将只复制到原始数组的对象的引用,并把它们放到新的数组中。

结果是:

 NSArray* myArray; NSMutableArray* anotherArray = [myArray mutableCopy]; [[anotherArray objectAtIndex:0] doSomething]; 

也会影响原始数组中索引为0的对象。


深层复制实际上将复制包含在数组中的单个对象。 这通过发送每个单独的对象“copyWithZone:”消息来完成。

 NSArray* myArray; NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:myArray copyItems:YES]; 

编辑删除我有关可变对象复制的错误的假设

 NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES]; 

将创buildanotherArray ,这是anotherArray的副本, oldArray为2级。 如果oldArray的对象是一个数组。 在大多数应用中通常是这种情况。

那么如果我们需要一个真正的深度拷贝

 NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject: oldArray]]; 

这将确保所有级别实际上被复制,以保持每个级别的原始对象的可变性。

印度class加罗尔的Robert Clarence D'Almeida。

你在原始数组上调用addObject和removeObjectAtIndex,而不是你创build的新副本。 调用副本vs mutableCopy只影响对象的新副本的可变性,而不是原始对象。

简单地说,

  • 复制返回一个不可变(不能被修改)的数组副本,
  • mutableCopy返回数组的可变(可修改)副本。

复制(在这两种情况下)意味着你得到一个新的数组“填充”与原始数组的对象引用(即在副本中引用相同(原始)对象。

如果将新对象添加到mutableCopy,那么它们对mutableCopy是唯一的。 如果从mutableCopy中删除对象,它们将从原始数组中删除。

把两种情况下的副本想象成创build副本时原始数组的快照。

承担

 NSArray *A = xxx; // A with three NSDictionary objects NSMutableArray *B = [A mutableCopy]; 

B的内容是NSDictionary对象而不是NSMutableDictionary,是不是?

 -(id)copy always returns a immutable one & -(id)mutableCopy always returns a mutable object,that's it. 

你必须知道这些复制东西的返回types,而声明新的对象将被赋予返回值必须是不可变或可变的,否则编译器会显示错误。

已经被复制的对象不能用新的对象修改,现在它们完全是两个不同的对象。