Копирование многомерного NSMutableArray - PullRequest
1 голос
/ 03 августа 2010

Я сейчас работаю над приложением Судоку, числа хранятся в многомерном NSMutableArray из NSNumbers. Я сохраняю массив в моем SudokuGridView для отображения чисел в сетке. Когда приходит время решить головоломку, я передаю [grid numberGrid] подклассу созданной мной NSOperation, который решает головоломку.

Массив сетки определяется как свойство следующим образом:

@property (readonly) NSMutableArray *numberArray; 

Передавая его в решатель судоку, я иду:

MESudokuSolver *solvePuzzleOperation  = [[MESudokuSolver alloc] initWithPuzzle: [grid numberArray]];

initWithPuzzle определяется так:

- (id)initWithPuzzle:(NSMutableArray *)puzzleArray  {
    if(self = [super init]) {
        puzzle = [[NSMutableArray alloc] initWithArray: puzzleArray];
    }
    return self;    
}

Когда я затем преобразую головоломку в примитивный массив int для ее решения, а затем снова возвращаюсь в головоломку NSMutableArray. Что забавно, так это то, что теперь NSMutableArray сетки теперь имеет решение ... Это означает, что каким-то образом внутри MESudokuSolver массив сетки изменяется. Поэтому я провел некоторое исследование, указатель на массив, который передается в экземпляр MESudokuSolver, отличается от головоломки NSMutableArray MESudokuSolver. Странно, правда? Я знаю.

После ДАЛЬНЕЙШЕГО расследования указатель на номера NSN в массивах с разными указателями фактически одинаков.

Вам StackOverflow, спрашиваю, WTF?

1 Ответ

1 голос
/ 03 августа 2010

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

// Implemented as a free function here, but this is not required.

NSMutableArray *MECopyGrid(NSMutableArray *outer)
{
    NSMutableArray *result = [[NSMutableArray alloc] initWithCapacity:[outer count]];

    for (NSMutableArray *inner in outer)
    {
        NSMutableArray *theCopy = [inner mutableCopy];
        [result addObject:theCopy];
        [theCopy release];
    }

    return result;
}

Остерегайтесь также оптимизаций NSNumber. Какао (и я предполагаю, что Cocoa Touch также) кэширует несколько разных экземпляров NSNumber. Поскольку экземпляры NSNumber являются неизменяемыми, если вы запрашиваете [NSNumber numberWithInteger:1], Какао может дать вам ссылку на существующий экземпляр, содержащий то же значение. Если вы заметили, что указатели экземпляра NSNumber совпадают, скорее всего, потому что Какао дал вам старый экземпляр. Это сэкономит память, особенно в таких ситуациях, как ваша (без оптимизации вам потребуется 81 независимый экземпляр NSNumber, но с оптимизацией вам потребуется не более 9).

...