1

現在、数独アプリケーションに取り組んでいます。数値は、NSNumbers の多次元 NSMutableArray 内に格納されています。グリッドに数字を表示するために、SudokuGridView に配列を保持しています。パズルを解くときが来たら、パズルを解くために作成した NSOperation のサブクラスに [グリッド numberGrid] を渡します。

グリッドの配列は、次のようにプロパティとして定義されます。

@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 インスタンスに渡される配列へのポインターは、MESudokuSolver のパズル NSMutableArray とは異なります。奇妙ですよね?知っている。

さらに調査すると、異なるポインターを持つ配列内の NSNumbers へのポインターは実際には同じです。

StackOverflow さん、お願いします。

4

1 に答える 1

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 (そして、Cocoa Touch もそうだと思います) は、いくつかの異なる NSNumber インスタンスをキャッシュします。NSNumber インスタンスは不変であるため、 を要求すると[NSNumber numberWithInteger:1]、Cocoa は同じ値を含む既存のインスタンスへの参照を提供する場合があります。NSNumber インスタンス ポインタが同じであることに気付いた場合は、Cocoa が古いインスタンスを提供したことが原因である可能性があります。これにより、特にあなたのような状況でメモリが節約されます (最適化がなければ、NSNumber の 81 個の独立したインスタンスが必要になりますが、最適化を使用すると、最大で 9 個しか必要ありません)。

于 2010-08-03T03:24:11.827 に答える