Глубокое копирование NSArray
есть ли встроенная функция, которая позволяет мне глубоко скопировать NSMutableArray
?
Я огляделся, некоторые говорят [aMutableArray copyWithZone:nil]
работает как глубокое копирование. Но я попытался, и это, кажется, мелкая копия.
сейчас я вручную делаю копию с for
петли:
//deep copy a 9*9 mutable array to a passed-in reference array
-deepMuCopy : (NSMutableArray*) array
toNewArray : (NSMutableArray*) arrayNew {
[arrayNew removeAllObjects];//ensure it's clean
for (int y = 0; y<9; y++) {
[arrayNew addObject:[NSMutableArray new]];
for (int x = 0; x<9; x++) {
[[arrayNew objectAtIndex:y] addObject:[NSMutableArray new]];
NSMutableArray *aDomain = [[array objectAtIndex:y] objectAtIndex:x];
for (int i = 0; i<[aDomain count]; i++) {
//copy object by object
NSNumber* n = [NSNumber numberWithInt:[[aDomain objectAtIndex:i] intValue]];
[[[arrayNew objectAtIndex:y] objectAtIndex:x] addObject:n];
}
}
}
}
но я хотел бы более чистое, более сжатое решение.
6 ответов:
Как Apple docs государство
Если вам нужна только одноуровневая глубокая копия, вы можете явно вызвать ее...
NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES];
приведенный выше код создает новый массив, члены которого являются мелкими копиями членов старого массива.
обратите внимание, что если вам нужно глубоко скопировать всю вложенную структуру данных - то, что связанные документы Apple называют "истинная глубокая копия" - тогда этого подхода будет недостаточно-см. другие ответы здесь.
единственный способ, который я знаю, чтобы легко сделать это, чтобы архивировать, а затем немедленно разархивировать массив. Это похоже на небольшой взлом, но на самом деле явно предлагается в документация Apple по копированию коллекций, в которой говорится:
Если вам нужна истинная глубокая копия, например, когда у вас есть массив массивов, вы можете архивировать, а затем разархивировать коллекцию, при условии, что все содержимое соответствует протоколу NSCoding. Примером такой техники является показано в листинге 3.
листинг 3 истинная глубокая копия
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
загвоздка в том, что ваш объект должен поддерживать интерфейс NSCoding, так как это будет использоваться для сохранения/загрузки данных.
Swift 2 Версия:
let trueDeepCopyArray = NSKeyedUnarchiver.unarchiveObjectWithData( NSKeyedArchiver.archivedDataWithRootObject(oldArray))
копировать по умолчанию дает мелкую копию
это потому, что вызов
copy
это то же самое, чтоcopyWithZone:NULL
также известный как копирование с зоной по умолчанию. Элементcopy
вызов не приводит к глубоким копированием. В большинстве случаев это даст вам мелкую копию, но в любом случае это зависит от класса. Для тщательного обсуждения я рекомендую Темы Программирования Коллекций на сайте разработчика Apple.initWithArray: CopyItems: дает один уровень глубоко копировать
NSArray *deepCopyArray = [[NSArray alloc] initWithArray:someArray copyItems:YES];
NSCoding
является ли Apple рекомендуемым способом обеспечить глубокую копиюдля истинной глубокой копии (массив массивов) вам понадобится
NSCoding
и архивировать/разархивировать объекта:NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
Для Словаря
NSMutableDictionary *newCopyDict = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)objDict, kCFPropertyListMutableContainers);
Для Выбора
NSMutableArray *myMutableArray = (NSMutableArray *)CFPropertyListCreateDeepCopy(NULL, arrData, kCFPropertyListMutableContainersAndLeaves);
нет, нет ничего встроенного в рамки для этого. Коллекции какао поддерживают мелкие копии (с
copy
илиarrayWithArray:
методы), но даже не говорите о глубокой концепции копирования.это потому, что" глубокая копия " начинает становиться трудно определить, как содержимое ваших коллекций начать в том числе ваших собственных пользовательских объектов. Означает ли "глубокая копия" объект в графе объектов является уникальной ссылкой относительно объект в исходном графе объекта?
Если бы была какая-то гипотетическая
NSDeepCopying
протокол, вы можете настроить это и принимать решения во всех ваших объектах, но, к сожалению, нет. если вы контролировали большинство объектов в своем графике, вы можете создать этот протокол самостоятельно и реализовать его, но вам нужно будет добавить категорию В базовые классы по мере необходимости.ответ@AndrewGrant, предполагающий использование ключевого архивирования/неархивирования, является несовершенным, но правильным и чистый способ достижения этого для произвольных объектов. эта книга даже заходит так далеко, чтобы предложить добавление категории ко всем объектам, которая делает именно это для поддержки глубокого копирования.
у меня есть обходной путь, если вы пытаетесь достичь глубокой копии для совместимых с JSON данных.
просто взять
NSData
ofNSArray
используяNSJSONSerialization
а затем воссоздать объект JSON, это создаст полную новую и свежую копиюNSArray/NSDictionary
С новыми ссылками на память о них.но убедитесь, что объекты NSArray / NSDictionary и их дочерние элементы должны быть сериализуемыми JSON.
NSData *aDataOfSource = [NSJSONSerialization dataWithJSONObject:oldCopy options:NSJSONWritingPrettyPrinted error:nil]; NSDictionary *aDictNewCopy = [NSJSONSerialization JSONObjectWithData:aDataOfSource options:NSJSONReadingMutableLeaves error:nil];