Копирование NSArray с изменяемыми копиями исходных элементов

Самое большое отрицательное (32-битное) значение: -2147483648
(1 < < 31)

Самое большое положительное (32-битное) значение: 2147483647
~ (1 < < 31)

Мнемоника: "пьяный AKA роговой"

drunk ========= Drinking age is 21
AK ============ AK 47
A ============= 4 (A and 4 look the same)
horny ========= internet rule 34 (if it exists, there's 18+ material of it) 

21 47 4(years) 3(years) 4(years)
21 47 48       36       48
11
задан Quinn Taylor 28 July 2009 в 16:09
поделиться

4 ответа

Другой подход, который вы можете предпринять, - использовать функцию CFPropertyListCreateDeepCopy () (в структуре CoreFoundation), передав в kCFPropertyListMutableContainers в качестве аргумента mutabilityOption. Код будет выглядеть так:

NSMutableArray* originalArray;
NSMutableArray* newArray;

newArray = (NSMutableArray*)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFPropertyListRef)originalArray, kCFPropertyListMutableContainers);

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

14
ответ дан 3 December 2019 в 03:36
поделиться

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

Обычно, когда я вижу слова «массив словарей», я понимаю, что вы используете словари в качестве заменителей объектов модели. Не делай этого. Напишите свои собственные классы моделей; все становится намного проще, когда у вас есть собственные настраиваемые свойства и методы поведения для работы. (Некоторых вещей больше, чем других: реализация поддержки AppleScript практически невозможна без надлежащего уровня модели.)

И когда у вас есть реальные объекты модели, вы можете реализовать в них NSCopying , и вам не придется беспокоиться об изменении и неизменности, поскольку в любом случае у вас, вероятно, не будет различия в изменчивости в реальных классах модели. (Не знаю, как другие, но я никогда не делал такого различия в своих модельных классах.) Тогда вы можете просто использовать существующий метод NSArray initWithArray: copyItems: .

5
ответ дан 3 December 2019 в 03:36
поделиться

При копировании массива будет создана копия объекта массива со ссылками на исходные объекты содержимого (сохраненные надлежащим образом).

Согласно документации, -initWithArray: copyItems: инициализирует новый массив копиями элементов исходного массива. Эта копия создается путем отправки исходных объектов содержимого -copyWithZone: , которые создают неизменяемую копию в случае изменяемых объектов.

Если вам нужно другое поведение (например, изменяемые копии объектов содержимого или глубокие копии объектов содержимого), вам нужно будет написать для этого свою собственную удобную функцию / метод.

6
ответ дан 3 December 2019 в 03:36
поделиться

Джим прав насчет -initWithArray: copyItems , отправляющего -copy сообщение каждому элементу. Чтобы получить изменяемые копии элементов массива, вам нужно отправить -mutableCopyWithZone: (или просто -mutableCopy для краткости) каждому элементу. Это довольно просто:

NSMutableArray *masterArray = ...
NSMutableArray *clone = [NSMutableArray arrayWithCapacity:[masterArray count]];
for (id anObject in masterArray)
    [clone addObject:[anObject mutableCopy]]; // OR [clone addObject:anObject];

Однако в вашем объяснении проблемы скрывается более глубокий вопрос: кажется, вы хотите, чтобы и массив, и его элементы (словари) были изменяемыми, но есть несколько тонких моментов, которые должны быть прояснено, особенно в свете вашего условия, что «[] копия, которая передается другим объектам, должна быть изменена без изменения оригинала». В зависимости от того, что именно вы имеете в виду, это может быть довольно сложно гарантировать и реализовать.

Например, предположим, что исходный массив содержит несколько изменяемых словарей. Создание изменяемых копий этих первых двух уровней означает, что кто-то, получивший копию, может изменять свой собственный массив и словари в массиве, не изменяя напрямую исходный массив или словарь. Однако, если словарь содержит изменяемые объекты (например, NSMutableArray, NSMutableString и т. д.), код, использующий «копию», может изменять содержимое словаря косвенно, используя только ссылку на изменяемую копию.

Изменяемые копии являются «неглубокими» ", то есть копируется только первый уровень, а копия имеет указатели на те же элементы, что и исходная структура. Таким образом, гарантия отсутствия связи между оригиналом и копией (по крайней мере, вручную) потребует просмотра всей структуры и создания копий. Это может стать более сложным, если некоторые элементы не соответствуют NSCopying или NSMutableCopying.

Самым простым и быстрым решением является использование простого кода, приведенного выше, или просто возврат ссылки на главный массив. Это требует уверенности в том, что клиентский код не будет изменять массив, поэтому это может работать не во всех ситуациях, но если вы также управляете вызывающим кодом, это может быть предпочтительнее. С другой стороны, если вам определенно нужна полностью отдельная копия, подумайте об использовании NSCoding / ключевого архивирования:

NSMutableArray *masterArray = ...
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:masterArray];
NSMutableArray *clone = [NSKeyedUnarchiver unarchiveObjectWithData:data];

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

рассмотрите возможность использования NSCoding / ключевого архивирования:

NSMutableArray *masterArray = ...
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:masterArray];
NSMutableArray *clone = [NSKeyedUnarchiver unarchiveObjectWithData:data];

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

рассмотрите возможность использования NSCoding / ключевого архивирования:

NSMutableArray *masterArray = ...
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:masterArray];
NSMutableArray *clone = [NSKeyedUnarchiver unarchiveObjectWithData:data];

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

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

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

2
ответ дан 3 December 2019 в 03:36
поделиться