在copy
或mutableCopy
上使用NSArray
和NSMutableArray
时有什么区别?
这是我的理解;这是对的吗?
// ** 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
答案 0 :(得分:72)
copy
和mutableCopy
在不同的协议中定义(分别为NSCopying
和NSMutableCopying
),NSArray
符合两者。 mutableCopy
的定义NSArray
(不仅仅是NSMutableArray
),并且允许您创建最初不可变数组的可变副本:
// 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"];
摘要:
mutableCopy
的结果变得可变。对于数组,结果应为NSMutableArray
。copy
的结果是可变的! copy
NSMutableArray
{/ 1}可以返回NSMutableArray
,因为这是原始类,但copy
任意NSArray
个实例都会copy
不 编辑:根据Mark Bessey的回答重新阅读原始代码。当您创建阵列的副本时,无论您对副本执行什么操作,当然您仍然可以修改原件。 mutableCopy
vs NSMutableArray -copy
会影响新数组是否可变。
修改2:修正了NSMutableArray
将返回{{1}}的假设(假设)。
答案 1 :(得分:8)
我认为你必须误解了copy和mutableCopy的工作原理。在第一个示例中,myArray_COPY是myArray的不可变副本。制作副本后,您可以操作原始myArray的内容,而不会影响myArray_COPY的内容。
在第二个示例中,您创建了myArray的可变副本,这意味着您可以修改数组的任一副本,而不会影响另一个副本。
如果我更改第一个示例以尝试从myArray_COPY插入/删除对象,它就会失败,就像您期望的那样。
或许考虑一个典型的用例会有所帮助。通常情况下,您可能会编写一个采用NSArray *
参数的方法,并且基本上将其存储以供以后使用。你可以这样做:
- (void) doStuffLaterWith: (NSArray *) objects {
myObjects=[objects retain];
}
...但是你遇到的问题是可以使用NSMutableArray作为参数调用该方法。创建数组的代码可以在调用doStuffLaterWith:方法之间以及稍后需要使用该值时对其进行操作。在多线程应用程序中,当你迭代它时,甚至可以更改的数组内容,这可能会导致一些有趣的错误。
如果您改为这样做:
- (void) doStuffLaterWith: (NSArray *) objects {
myObjects=[objects copy];
}
..然后副本会在调用方法时创建数组内容的快照。
答案 2 :(得分:5)
“copy”方法返回通过实现NSCopying协议copyWithZone创建的对象:
如果您向NSString发送一条复制邮件:
NSString* myString;
NSString* newString = [myString copy];
返回值将是NSString(不可变)
mutableCopy方法返回通过实现NSMutableCopying协议的mutableCopyWithZone创建的对象:
发送:
NSString* myString;
NSMutableString* newString = [myString mutableCopy];
返回值 WILL 是可变的。
在所有情况下,对象必须实现协议,表示它将创建新的复制对象并将其返回给您。
在NSArray的情况下,浅层和深层复制存在额外的复杂程度。
NSArray的浅表副本只会复制对原始数组对象的引用,并将它们放入新数组中。
结果是:
NSArray* myArray;
NSMutableArray* anotherArray = [myArray mutableCopy];
[[anotherArray objectAtIndex:0] doSomething];
还会影响原始数组中索引0处的对象。
深层副本实际上会复制数组中包含的各个对象。这是通过向每个单独的对象发送“copyWithZone:”消息来完成的。
NSArray* myArray;
NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:myArray
copyItems:YES];
编辑删除我对可变对象复制的错误假设
答案 3 :(得分:5)
NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray
copyItems:YES];
将创建anotherArray
,这是oldArray
到2级深度的副本。如果oldArray
的对象是数组。在大多数应用中通常都是这种情况。
如果我们需要 True Deep Copy ,我们可以使用,
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
[NSKeyedArchiver archivedDataWithRootObject: oldArray]];
这将确保实际复制所有级别,保留每个级别的原始对象的可变性。
Robert Clarence D'Almeida, 印度班加罗尔。
答案 4 :(得分:3)
您在原始数组上调用addObject和removeObjectAtIndex,而不是您创建的新副本。调用copy vs mutableCopy只会影响对象的新副本的可变性,而不会影响原始对象。
答案 5 :(得分:2)
简单说明,
复制(在这两种情况下)意味着你得到一个新阵列"填充"对象引用原始数组(即副本中引用相同(原始)对象。
如果向mutableCopy添加新对象,则它们对mutableCopy是唯一的。如果从mutableCopy中删除对象,则会从原始数组中删除它们。
在两种情况下都考虑副本,作为创建副本时原始数组的时间快照。
答案 6 :(得分:0)
假设
NSArray *A = xxx; // A with three NSDictionary objects
NSMutableArray *B = [A mutableCopy];
B的内容是NSDictionary对象而不是NSMutableDictionary,是不是?
答案 7 :(得分:0)
-(id)copy always returns a immutable one & -(id)mutableCopy always returns a mutable object,that's it.
你必须知道这些复制内容的返回类型,并且在声明新对象时,返回值必须是不可变的或可变的,否则编译器会显示错误。
已复制的对象无法使用新对象进行修改,现在它们完全是两个不同的对象。