Jim は、各要素にメッセージを-initWithArray:copyItems
送信することについて正しいです。-copyWithZone:
配列要素の変更可能なコピーを取得するには、各要素に送信する必要があります-mutableCopyWithZone:
(または-mutableCopy
簡潔にするために)。これはかなり簡単です。
NSMutableArray *masterArray = ...
NSMutableArray *clone = [NSMutableArray arrayWithCapacity:[masterArray count]];
for (id anObject in masterArray)
[clone addObject:[anObject mutableCopy]]; // OR [clone addObject:anObject];
ただし、問題の説明にはより深い質問が隠されています。配列とその要素 (辞書) の両方を可変にしたいようですが、特にあなたの「他のオブジェクトに渡されるコピーは、オリジナルを変更せずに変更する必要がある」という規定。正確に何を意味するかに応じて、これを保証して実装するのは非常に複雑になる可能性があります。
たとえば、元の配列に多数の変更可能な辞書が含まれているとします。これらの最初の 2 つのレベルの変更可能なコピーを作成するということは、コピーを取得したユーザーが、元の配列や辞書を直接変更することなく、独自の配列と配列内の辞書を変更できることを意味します。ただし、ディクショナリに変更可能なオブジェクト (NSMutableArray、NSMutableString など) が含まれている場合、「コピー」を使用するコードは、変更可能なコピーへの参照のみを使用して、間接的にディクショナリの内容を変更できます。
変更可能なコピーは「浅い」ものです。つまり、最初のレベルのみがコピーされ、コピーには元の構造と同じ要素へのポインターがあります。したがって、オリジナルとコピーの間にリンクがないことを (少なくとも手動で) 保証するには、構造全体を一掃してコピーを作成する必要があります。一部の要素が NSCopying または NSMutableCopying に準拠していない場合、これはさらに複雑になる可能性があります。
最も簡単で最速の解決策は、上記の単純なコードを使用するか、単にマスター配列への参照を返すことです。これには、クライアント コードが配列を変更しないことを信頼する必要があるため、これはすべての状況で機能するとは限りませんが、呼び出しコードも制御する場合は、これが望ましい場合があります。一方、絶対に完全に別のコピーが必要な場合は、NSCoding / キー付きアーカイブの利用を検討してください。
NSMutableArray *masterArray = ...
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:masterArray];
NSMutableArray *clone = [NSKeyedUnarchiver unarchiveObjectWithData:data];
基本的に、これはすべてを生データバイトに変換し、それを新しいオブジェクトのセットに再構成します。これが機能するには、辞書内のすべてのオブジェクトがNSCoding プロトコルに準拠している必要があります。これには少し時間がかかる場合がありますが、オブジェクトの一意性を保証するための洗練された一般的な方法です。これには確かにパフォーマンス コストがゼロではありませんが、副作用がないことを絶対に保証する必要がある場合は、機能するはずです。