Как копировать и 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
8 64

8 ответов:

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

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

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

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

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

Если я изменю первый пример, чтобы попытаться вставка / удаление объектов из myArray_COPY, это не удается, как и следовало ожидать.


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

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

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

NSString* myString;

NSString* newString = [myString copy];

возвращаемое значение будет NSString (not mutable)


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

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

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

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

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

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

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

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

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

сказать это просто,

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

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

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

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

предположим

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.

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

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