как copy и mutablecopy применяются к nsarray и nsmutablearray?

<p>в чем разница между <code>copy</code> и <code>mutablecopy</code> при использовании в <code>nsarray</code> или <code>nsmutablearray</code>?</p><p>это мое понимание; это правильно?</p><pre><code>// ** 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 </code></pre><hr><pre><code>// ** 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 </code></pre>

<p><code>copy</code> и <code>mutablecopy</code> определены в разных протоколах (<code>nscopying</code> и <code>nsmutablecopying</code> соответственно), а <code>nsarray</code> соответствует обоим. <code>mutablecopy</code> определен для <code>nsarray</code> (а не только <code>nsmutablearray</code>) и позволяет вам сделать изменяемую копию первоначально неизменяемого массива:</p><pre><code>// 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"]; </code></pre><p>резюме: </p><ul> <li>вы можете зависеть от того, что результат <code>mutablecopy</code> будет изменчивым, независимо от исходного типа. в случае массивов результат должен быть <code>nsmutablearray</code>.</li> <li>вы <em>не можете</em> полагаться на то, что результат <code>copy</code> будет изменчивым! <code>copy</code>ing <code>nsmutablearray</code> <em>может</em> возвращать <code>nsmutablearray</code>, поскольку это исходный класс, но <code>copy</code>ing для любого произвольного экземпляра <code>nsarray</code> не будет.</li> </ul><p><strong> правка: </strong>перечитать ваш оригинальный код в свете ответа марка бесси. когда вы создаете копию массива, вы, конечно, можете изменить оригинал независимо от того, что вы делаете с копией. <code>copy</code> vs <code>mutablecopy</code> влияет на то, является ли массив <em>new</em> изменчивым.</p><p><strong> правка 2: </strong>исправлено мое (ложное) предположение, что <code>nsmutablearray -copy</code> вернет <code>nsmutablearray</code>.</p>

<p>я думаю, что вы, должно быть, неправильно истолковали, как работают copy и mutablecopy. в вашем первом примере myarray\_copy является неизменной копией myarray. сделав копию, вы можете манипулировать содержимым оригинала myarray и не влиять на содержимое myarray\_copy. </p><p>во втором примере вы создаете изменяемую копию myarray, что означает, что вы можете изменить любую копию массива, не затрагивая другую.</p><p>если я изменю первый пример, чтобы попытаться вставить/удалить объекты из myarray\_copy, произойдет сбой, как и следовало ожидать.</p><hr><p>возможно, размышление о типичном сценарии использования поможет. часто бывает, что вы можете написать метод, который принимает параметр <code>nsarray *</code> и в основном сохраняет его для дальнейшего использования. вы можете сделать это следующим образом:</p><pre><code>- (void) dostufflaterwith: (nsarray *) objects { myobjects=[objects retain]; } </code></pre><p>... но тогда у вас есть проблема, что метод может быть вызван с nsmutablearray в качестве аргумента. код, создавший массив, может манипулировать им между тем, когда вызывается метод dostufflaterwith:, и когда вам позже потребуется использовать значение. в многопоточном приложении содержимое массива может быть даже изменено<em> пока вы выполняете итерации по нему </em>, что может вызвать некоторые интересные ошибки.</p><p>если вы вместо этого сделаете это:</p><pre><code>- (void) dostufflaterwith: (nsarray *) objects { myobjects=[objects copy]; } </code></pre><p>.. тогда копия создает снимок содержимого массива во время вызова метода.</p>

<p>метод «copy» возвращает объект, созданный путем реализации протоколов nscopying copywithzone:</p><p>если вы отправляете nsstring копию сообщения:</p><pre><code>nsstring* mystring; nsstring* newstring = [mystring copy]; </code></pre><p>возвращаемым значением будет строка nsstring (не изменяемая)</p><hr><p>метод mutablecopy возвращает объект, созданный путем реализации mutablecopywithzone протокола nsmutablecopying:</p><p>отправив:</p><pre><code>nsstring* mystring; nsmutablestring* newstring = [mystring mutablecopy]; </code></pre><p>возвращаемое значение<strong>будет</strong>будет изменяемым.</p><hr><p>во всех случаях объект должен реализовывать протокол, означающий, что он создаст новый объект-копию и вернет его вам.</p><hr><p>в случае nsarray существует дополнительный уровень сложности в отношении мелкого и глубокого копирования.</p><p>мелкая копия nsarray будет копировать только ссылки на объекты исходного массива и помещать их в новый массив.</p><p>результат таков:</p><pre><code>nsarray* myarray; nsmutablearray* anotherarray = [myarray mutablecopy]; [[anotherarray objectatindex:0] dosomething]; </code></pre><p>также повлияет на объект с индексом 0 в исходном массиве.</p><hr><p>глубокая копия фактически скопирует отдельные объекты, содержащиеся в массиве. это делается путем отправки каждому отдельному объекту сообщения «copywithzone:».</p><pre><code>nsarray* myarray; nsmutablearray* anotherarray = [[nsmutablearray alloc] initwitharray:myarray copyitems:yes]; </code></pre><p>отредактировано, чтобы убрать мое неверное предположение о копировании изменяемого объекта</p>

<pre><code>nsmutablearray* anotherarray = [[nsmutablearray alloc] initwitharray:oldarray copyitems:yes]; </code></pre><p>создаст <code>anotherarray</code>, который является копией <code>oldarray</code> до 2 уровней. если объект <code>oldarray</code> является массивом. что обычно имеет место в большинстве приложений.</p><p>ну, если нам нужен<strong> true deep copy </strong>мы могли бы использовать,</p><pre><code>nsarray* truedeepcopyarray = [nskeyedunarchiver unarchiveobjectwithdata: [nskeyedarchiver archiveddatawithrootobject: oldarray]]; </code></pre><p>это обеспечит копирование всех уровней, сохраняя изменчивость исходного объекта на каждом уровне.</p><p>роберт кларенс д'алмейда, бангалор, индия.</p>

<p>вы вызываете addobject и removeobjectatindex для исходного массива, а не для новой копии, которую вы сделали. вызов copy против mutablecopy влияет только на изменчивость новой копии объекта, а не исходного объекта.</p>

<p>чтобы заявить это просто, </p><ul> <li>copy возвращает неизменяемую (не может быть изменена) копию массива, </li> <li>mutablecopy возвращает изменяемую (может быть изменена) копию массива. </li> </ul><p>копирование (в обоих случаях) означает, что вы получаете новый массив, «заполненный» ссылками на исходный массив (то есть те же (оригинальные) объекты, на которые ссылаются копии). </p><p>если вы добавляете новые объекты в mutablecopy, то они уникальны для mutablecopy. если вы удаляете объекты из mutablecopy, они удаляются из исходного массива. </p><p>представьте себе копию в обоих случаях как моментальный снимок исходного массива во время создания копии.</p>

<pre><code>-(id)copy always returns a immutable one & -(id)mutablecopy always returns a mutable object,that's it. </code></pre><p>вы должны знать тип возврата этих копирующих материалов, и при объявлении нового объекта, которому будет присвоен объект, возвращаемое значение должно быть неизменным или изменяемым, иначе компилятор покажет вам ошибку.</p><p>скопированный объект не может быть изменен с помощью нового, теперь это два совершенно разных объекта.</p>

<p>предполагать </p><pre><code>nsarray *a = xxx; // a with three nsdictionary objects nsmutablearray *b = [a mutablecopy]; </code></pre><p>содержание b - это объект nsdictionary, а не nsmutabledictionary, верно?</p>