2010-08-03 3 views
1

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

массив Сетка является определяется как свойство, как например:

@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, чтобы решить ее, а затем обратно в головоломку NSMutab leArray. Что смешно, так это то, что теперь NSMutableArray сетки имеет решение ... Это означает, что каким-то образом внутри MESudokuSolver изменяется сетка сетки. Поэтому я провел некоторое расследование, указатель на массив, который передается в экземпляр MESudokuSolver, отличается от головоломки NSMutableArray от MESudokuSolver. Странно, правда? Я знаю.

При исследовании FURTHER указатель на NSNumbers внутри массивов с разными указателями на самом деле является ТО ЖЕ.

Для вас StackOverflow, спрашиваю, WTF?

ответ

1

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

// 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], Cocoa может дать вам ссылку на существующий экземпляр, содержащий одно и то же значение. Если вы заметили, что указатели экземпляра NSNumber одинаковы, это, скорее всего, потому, что Cocoa предоставил вам старый экземпляр. Это экономит память, особенно в ситуациях, подобных вашим (без оптимизаций вам понадобится 81 независимый экземпляр NSNumber, но с оптимизацией вам понадобится не более 9).

+0

Спасибо! Я никогда не сталкивался с этой проблемой раньше, вероятно, потому, что раньше я никогда не работал с многомерными NSArrays. Если бы я мог задать быстрый вопрос, чтобы прояснить здесь ... почему это так, если у вас есть одномерный массив, говорящий о ... NSStrings, что эти строки фактически скопированы в память и не изменены непосредственно из другого экземпляра? –

+0

@Matt Egan: Я не совсем уверен, что вы имеете в виду. Если у вас есть массив неизменяемых строк, они, вероятно, никогда не будут скопированы в память. Поскольку ничто не может изменять неизменяемую строку, «копия» становится простой «сохранить». Если вы создадите копию массива, содержащую неизменяемые строки, оба массива будут содержать ссылки на те же неизменяемые строки. Единственный момент, когда изменение объектов вызывает беспокойство, - это когда ваш массив содержит * изменяемые * объекты. Если вы хотите, чтобы объект поддерживал mutable, но вы ничего не хотите изменить, вы должны получить 'mutableCopy'. – dreamlax

+0

Это имеет смысл, еще раз спасибо! –