it-swarm.com.ru

Как 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
64
fuzzygoat

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

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

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

71
Asher Dunn

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

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

8
Mark Bessey

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

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

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

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

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

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

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

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

5
robertt almeida

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

3
Dewayne Christensen

Чтобы заявить это просто, 

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

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

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

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

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

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

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

0
Sauvik Dolui

Предполагать 

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

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

0
ZYiOS