Как copy и mutableCopy применяются к NSArray и NSMutableArray? - PullRequest
65 голосов
/ 04 января 2010

В чем разница между 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

Ответы [ 8 ]

72 голосов
/ 05 января 2010

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 может вернуть NSMutableArray, поскольку это исходный класс, но copy любой произвольный NSArray экземпляр не будет.

Редактировать: перечитать исходный код в свете ответа Марка Бесси. Когда вы создаете копию массива, вы, конечно, можете изменить оригинал независимо от того, что вы делаете с копией. copy против mutableCopy влияет на то, является ли новый массив изменяемым.

Редактировать 2: Исправлено мое (ложное) предположение, что NSMutableArray -copy вернет NSMutableArray.

8 голосов
/ 05 января 2010

Я думаю, вы, должно быть, неверно истолковали, как работают 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];
}

.. затем копия создает снимок содержимого массива во время вызова метода.

5 голосов
/ 02 сентября 2011
NSMutableArray* anotherArray = [[NSMutableArray alloc] initWithArray:oldArray
                                                           copyItems:YES];

создаст anotherArray, который является копией oldArray на 2 уровня глубины. Если объект oldArray является массивом. Что обычно имеет место в большинстве приложений.

Ну, если нам понадобится True Deep Copy , мы могли бы использовать,

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

Это обеспечит копирование всех уровней, сохраняя изменчивость исходного объекта на каждом уровне.

Роберт Кларенс д'Альмейда, Бангалор, Индия.

5 голосов
/ 05 января 2010

Метод «copy» возвращает объект, созданный путем реализации протоколов NSCopying copyWithZone:

Если вы отправляете NSString сообщение о копировании:

NSString* myString;

NSString* newString = [myString copy];

Возвращаемым значением будет строка NSString (не изменяемая)


Метод mutableCopy возвращает объект, созданный путем реализации mutableCopyWithZone протокола NSMutableCopying:

Отправив:

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];

Отредактировано для удаления моего неверного предположения о копировании изменяемого объекта

3 голосов
/ 05 января 2010

Вы вызываете addObject и removeObjectAtIndex для исходного массива, а не для новой копии, которую вы сделали. Вызов copy против mutableCopy влияет только на изменчивость новой копии объекта, а не исходного объекта.

2 голосов
/ 05 июля 2014

Проще говоря,

  • copy возвращает неизменную (не может быть изменена) копию массива,
  • mutableCopy возвращает изменяемую (может быть изменена) копию массива.

Копирование (в обоих случаях) означает, что вы получаете новый массив, «заполненный» ссылками на объекты исходного массива (то есть те же (оригинальные) объекты, на которые ссылаются копии).

Если вы добавляете новые объекты в mutableCopy, то они уникальны для mutableCopy. Если вы удалите объекты из mutableCopy, они будут удалены из исходного массива.

Думайте о копии в обоих случаях как о снимке во времени исходного массива на момент создания копии.

0 голосов
/ 07 августа 2013
-(id)copy always returns a immutable one & -(id)mutableCopy always returns a mutable object,that's it.

Вы должны знать тип возврата этих копируемых материалов, и при объявлении нового объекта, которому будет присвоен объект, возвращаемое значение должно быть неизменным или изменяемым, иначе компилятор покажет вам ошибку.

Скопированный объект не может быть изменен с помощью нового, теперь это абсолютно разные объекты.

0 голосов
/ 12 мая 2011

Предположим,

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

Содержимое B - это объект NSDictionary, а не NSMutableDictionary, верно?

...