Вопрос

Есть ли какая-либо встроенная функция, которая позволяет мне глубоко копировать 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];
            }
        }
    }
}

но мне бы хотелось более чистого и лаконичного решения.

Это было полезно?

Решение

Как штат Apple Docs ,

  

Если вам нужна только одноуровневая копия, вы можете явно вызвать одну ...

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

Приведенный выше код создает новый массив, члены которого являются мелкими копиями членов старого массива.

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

Другие советы

Единственный способ, который я знаю, - это заархивировать и сразу же разархивировать ваш массив. Это похоже на хакерство, но на самом деле это явно предложено в / apple_ref / doc / uid / TP40010162-SW3 "rel =" noreferrer "> Документация 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 способ предоставления глубокой копии

Для истинного глубокого копирования (Array of Arrays) вам потребуется NSCoding и архивировать / разархивировать объект:

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

Для диктонары

NSMutableDictionary * newCopyDict = (NSMutableDictionary *) CFPropertyListCreateDeepCopy (kCFAllocatorDefault, (CFDictionaryRef) objDict, kCFPropertyListMutableContainers);

Для массива

NSMutableArray * myMutableArray = (NSMutableArray *) CFPropertyListCreateDeepCopy (NULL, arrData, kCFPropertyListMutableContainersAndLeaves);

Нет, в фреймворки для этого ничего не встроено.Коллекции Cocoa поддерживают неглубокие копии (с copy или тот arrayWithArray: методы), но даже не говорите о концепции глубокого копирования.

Это связано с тем, что определение термина "глубокое копирование" становится трудным по мере того, как содержимое ваших коллекций начинает включать ваши собственные пользовательские объекты.Означает ли "глубокое копирование" каждый объект в графе объектов является уникальной ссылкой относительно каждый объект в исходном графе объектов?

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

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

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

Просто возьмите NSData из NSArray используя 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];
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top