66

在 an或 an上使用copy和使用时有什么区别?mutableCopyNSArrayNSMutableArray

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

// ** 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
4

8 回答 8

73

copymutableCopy在不同的协议中定义(NSCopyingNSMutableCopying,分别),并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可变的结果!copying anNSMutableArray 可能会返回 an NSMutableArray,因为那是原始类,但copying 任何任意NSArray实例都不会。

编辑:根据 Mark Bessey 的回答重新阅读您的原始代码。当您创建阵列的副本时,当然,无论您对副本做什么,您仍然可以修改原始文件。copyvsmutableCopy影响新数组是否可变。

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

于 2010-01-04T21:11:06.993 回答
9

我认为您一定误解了 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];
}

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

于 2010-01-04T21:12:32.090 回答
5

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

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

NSString* myString;

NSString* newString = [myString copy];

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


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

通过发送:

NSString* myString;

NSMutableString* newString = [myString mutableCopy];

返回值是可变的。


在所有情况下,对象都必须实现协议,这意味着它将创建新的副本对象并将其返回给您。


在 NSArray 的情况下,浅层和深层复制的复杂程度更高。

NSArray 的浅拷贝只会复制对原始数组对象的引用并将它们放入新数组中。

结果是:

NSArray* myArray;

NSMutableArray* anotherArray = [myArray mutableCopy];

[[anotherArray objectAtIndex:0] doSomething];

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


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

NSArray* myArray;

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

编辑以消除我关于可变对象复制的错误假设

于 2010-01-04T21:25:47.417 回答
5
NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray
                                                           copyItems:YES];

将创建2 级深度anotherArray的副本。oldArray如果一个对象oldArray是一个数组。在大多数应用程序中通常是这种情况。

好吧,如果我们需要一个真正的深拷贝,我们可以使用,

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

这将确保实际复制所有级别,并在每个级别保留原始对象的可变性。

Robert Clarence D'Almeida,印度班加罗尔。

于 2011-09-02T16:06:54.873 回答
3

您在原始数组上调用 addObject 和 removeObjectAtIndex,而不是您制作的新副本。调用 copy vs mutableCopy 只会影响对象新副本的可变性,而不是原始对象。

于 2010-01-04T22:56:23.287 回答
2

简单地说,

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

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

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

将这两种情况下的副本视为创建副本时原始阵列的时间快照。

于 2014-07-05T11:57:02.417 回答
0
-(id)copy always returns a immutable one & -(id)mutableCopy always returns a mutable object,that's it.

您必须知道这些复制内容的返回类型,并且在声明将分配哪个新对象时,返回值必须是不可变或可变的,否则编译器会显示错误。

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

于 2013-08-07T06:28:30.247 回答
0

认为

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

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

于 2011-05-12T04:28:36.963 回答