121

ディープコピーを可能にする組み込み関数はあります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];
            }
        }
    }
}

しかし、私はよりクリーンで簡潔な解決策が欲しいのです。

4

6 に答える 6

214

ディープコピーに関するAppleのドキュメントには、次のように明示されています。

1レベルの深さのコピーのみが必要な場合:

NSMutableArray *newArray = [[NSMutableArray alloc] 
                             initWithArray:oldArray copyItems:YES];

上記のコードは、メンバーが古い配列のメンバーの浅いコピーである新しい配列を作成します。

ネストされたデータ構造全体(リンクされたAppleドキュメントで真のディープコピーと呼ばれるもの)をディープコピーする必要がある場合は、このアプローチでは不十分であることに注意してください。それについては、ここで他の回答を参照してください。

于 2009-03-15T09:18:24.247 に答える
63

これを簡単に行う唯一の方法は、アレイをアーカイブしてからすぐにアーカイブを解除することです。ちょっとしたハックのように感じますが、実際にはコレクションのコピーに関する Apple ドキュメントで明示的に提案されています。

配列の配列がある場合など、真のディープ コピーが必要な場合は、コンテンツがすべて NSCoding プロトコルに準拠していれば、コレクションをアーカイブしてからアーカイブ解除できます。この手法の例をリスト 3 に示します。

リスト 3 真のディープ コピー

NSArray* trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:
          [NSKeyedArchiver archivedDataWithRootObject:oldArray]];

問題は、データの保存/読み込みに使用されるため、オブジェクトが NSCoding インターフェイスをサポートしている必要があることです。

スウィフト 2 バージョン:

let trueDeepCopyArray = NSKeyedUnarchiver.unarchiveObjectWithData(
    NSKeyedArchiver.archivedDataWithRootObject(oldArray))
于 2009-03-15T04:04:55.373 に答える
35

デフォルトでコピーは浅いコピーを提供します

これは、呼び出しが、デフォルト ゾーンでのコピーとも呼ばれるcopyのと同じであるためです。copyWithZone:NULLこのcopy呼び出しは、ディープ コピーにはなりません。ほとんどの場合、浅いコピーが得られますが、いずれにしてもクラスによって異なります。詳細については、Apple Developer サイトのCollections Programming Topicsをお勧めします。

initWithArray:CopyItems: 1 レベルのディープ コピーを提供します

NSArray *deepCopyArray = [[NSArray alloc] initWithArray:someArray copyItems:YES];

NSCodingディープコピーを提供するApple推奨の方法です

NSCoding真のディープ コピー (配列の配列) の場合は、オブジェクトをアーカイブ/アーカイブ解除する必要があります。

NSArray *trueDeepCopyArray = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:oldArray]];
于 2013-02-23T12:57:53.963 に答える
5

いいえ、このためのフレームワークに組み込まれたものはありません。copyCocoa コレクションは (またはメソッドを使用して) 浅いコピーをサポートしarrayWithArray:ますが、深いコピーの概念については触れません。

これは、コレクションのコンテンツに独自のカスタム オブジェクトが含まれ始めると、「ディープ コピー」の定義が難しくなり始めるためです。「ディープ コピー」とは、オブジェクト グラフ内のすべてのオブジェクトが、元のオブジェクト グラフ内のすべてのオブジェクトに対して一意の参照であることを意味しますか?

仮のプロトコルがあればNSDeepCopying、これを設定してすべてのオブジェクトで決定を下すことができますが、残念ながらそうではありません。グラフ内のほとんどのオブジェクトを制御する場合、このプロトコルを自分で作成して実装できますが、必要に応じて Foundation クラスにカテゴリを追加する必要があります。

キー付きアーカイブ/アーカイブ解除の使用を示唆する@A​​ndrewGrantの回答は、非パフォーマンスですが、任意のオブジェクトに対してこれを達成するための正しくてクリーンな方法です。この本はさらに行き過ぎているので、深いコピーをサポートするために、まさにそれを行うすべてのオブジェクトにカテゴリを追加することをお勧めします。

于 2013-11-02T15:26:30.673 に答える