复制和mutableCopy如何适用于NSArray和NSMutableArray?
在NSArray
或NSMutableArray
上使用copy
和mutableCopy
什么区别?
这是我的理解; 这是对的吗?
// ** 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
copy
和mutableCopy
定义在不同的协议(分别NSCopying
和NSMutableCopying
)和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,而声明新的对象将被赋予返回值必须是不可变或可变的,否则编译器会显示错误。
已经被复制的对象不能用新的对象修改,现在它们完全是两个不同的对象。