Как применить copy и mutableCopy к NSArray и NSMutableArray?

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

Ответ 1

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

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

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

Ответ 2

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

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

Ответ 3

Метод "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];

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

Ответ 4

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

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

Ну, если нам нужна True Deep Copy, которую мы могли бы использовать,

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

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

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

Ответ 5

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

Ответ 6

Чтобы просто сказать,

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

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

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

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

Ответ 7

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

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

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

Ответ 8

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

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

Объект, который был скопирован, не может быть изменен с использованием нового, теперь они полностью представляют собой два разных объекта.