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 状態として、
1レベルの深さのコピーのみが必要な場合は、1つを明示的に呼び出すことができます...
NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:oldArray copyItems:YES];
上記のコードは、メンバーが古い配列のメンバーの浅いコピーである新しい配列を作成します。
ネストされたデータ構造全体を深くコピーする必要がある場合-リンクされたApple docs calls "true deep copy"-このアプローチでは十分ではありません-他の回答を参照してください。
これを簡単に行える唯一の方法は、アレイをアーカイブしてからすぐにアーカイブ解除することです。ちょっとしたハックのように感じますが、実際には コレクションのコピーに関するAppleドキュメント で明示的に提案されています。
配列の配列がある場合など、真のディープコピーが必要な場合は、コンテンツがすべてNSCodingプロトコルに準拠していれば、コレクションをアーカイブしてからアーカイブ解除できます。この手法の例をリスト3に示します。
リスト3真のディープコピー
NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData: [NSKeyedArchiver archivedDataWithRootObject:oldArray]];
キャッチは、オブジェクトがNSCodingインターフェースをサポートする必要があることです。これは、データの保存/ロードに使用されるためです。
let trueDeepCopyArray = NSKeyedUnarchiver.unarchiveObjectWithData(
NSKeyedArchiver.archivedDataWithRootObject(oldArray))
これは、copy
の呼び出しがcopyWithZone:NULL
と同じであり、デフォルトゾーンでのコピーとしても知られているためです。 copy
呼び出しでは、ディープコピーは行われません。ほとんどの場合、それは浅いコピーを提供しますが、いずれにしてもクラスに依存します。徹底的な議論のために、Apple Developerサイトで Collections Programming Topics をお勧めします。
NSArray *deepCopyArray = [[NSArray alloc] initWithArray:someArray copyItems:YES];
NSCoding
はAppleディープコピーを提供する推奨方法です真のディープコピー(配列の配列)には、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:
メソッド)が、ディープコピーの概念については説明しません。
これは、独自のカスタムオブジェクトを含むコレクションのコンテンツが開始されると、「ディープコピー」の定義が困難になるためです。 「ディープコピー」とは、オブジェクトグラフ内のeveryオブジェクトがevery元のオブジェクトグラフのオブジェクト?
仮想NSDeepCopying
プロトコルがある場合、これを設定してすべてのオブジェクトで決定を下すことができますが、残念ながらありません。グラフ内のほとんどのオブジェクトを制御した場合、このプロトコルを自分で作成して実装できますが、必要に応じてFoundationクラスにカテゴリを追加する必要があります。
キー付きアーカイブ/アーカイブ解除の使用を示唆する@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];