0

Stanford iTunes から Objective-C を学びましたが、初期化せずに NSMutableArray を NSArray にコピーする方法を知りたいです。つまり:

これは正しいですか?「遅延初期化」で。

-(void)copyAnArray:(NSMutableArray*)listOfElements {
    if(privateElementsLists == nil)
        privateElementsLists = [[NSArray alloc] initWithArray:listOfElements copyItems:YES];
    else
        privateElementsLists = listOfElements;
}

これは悪い設計ですか?オブジェクトを 1 つのクラスの可変配列に追加し、終了したら NSMutableArray 全体を NSArray にコピーします。

もう 1 つの質問: copyItems:YESinitWithArray を使用するときに使用する必要があるのはなぜですか? ディープコピーとは?

4

2 に答える 2

2

Joseph DeCarloが述べたように、ある場所で配列を作成して別の場所で使用するだけの場合は、にコピーNSMutableArrayする必要はありません。NSArrayたとえば、次のステートメントは有効です。

NSArray* newArray = [NSMutableArray array];

またはコード内:

-(NSArray*)returnAnArray
{
    NSMutableArray* editableArray = [NSMutableArray array];
    [editableArray addObject:[[NSObject alloc] init]]; //an exemplary object added to the array
    return editableArray;
}

ただし、元の配列がインスタンス変数に格納されている場合など、特定のケースでは、NSMutableArrayへのキャストが安全でない場合があります。NSArrayその配列にオブジェクトを追加したり、その配列からオブジェクトを削除したりすると、返された配列が同時に列挙された場合にクラッシュが発生する可能性があります。例えば:

-(void)createArray
{
    self->editableArray = [NSMutableArray array]; // instance variable: NSMutableArray* editableArray
}

-(void)addObjectToArray
{
    [self->editableArray addObject:[[NSObject alloc] init]];
}

-(NSArray*)getArray
{
    return self->editableArray;
}

-(void)enumerateArray
{
    for(NSObject obj in [self getArray])
    {
        // do something with obj
    }
}

addObjectToArray(バックグラウンドスレッドなどから)同時に呼び出された場合enumerateArray、列挙中に基になる配列が変更されるため、アプリケーションがクラッシュします。として返されるかどうかは関係ありませんNSArray*。このような場合@synchronized、複数のスレッドによる同じオブジェクトへのアクセスを同期するために追加するかarrayWithArray:、提案されているように配列全体をコピーする必要があります。ただし、ドキュメントにはスレッドセーフかどうかが記載されていないため、とにかく呼び出しをarrayWithArray:追加します。@synchronizedarrayWithArray:

于 2012-04-17T12:58:33.233 に答える
2

initWithArray: または次の方法で、変更可能な配列を新しい配列にコピーできます。

privateElementsLists = [NSArray arrayWithArray:listOfElements];

次に、その各要素が元の配列に含まれる同じオブジェクトである新しい配列を作成しています。あなたが書く場合:

privateElementsLists = [NSArray arrayWithArray:listOfElements copyItems:YES];

次に、新しい配列には、要素ごとに、元の配列の要素のコピーがあります。それらは同じオブジェクトではなく、コピーです。もちろん、そのオブジェクトはコピーに応答できなければなりません。

これを行うこともできます:

privateElementsLists = (NSArray*) listOfElements ;

その後、配列は元の配列とまったく同じです。ここには新しい配列はありません。しかし、NSArray ポインタ クラスでキャストしたので、NSMutableArray ではなく NSArray であるかのように使用できます。ご存知のように、すべての NSMutableArray は NSArray (継承されたクラス) です。

于 2012-04-17T10:59:40.580 に答える