0

NSMutableDictionaryと呼ばれるを設定するシングルトンクラスがありcompletedLevelsます。

これは私がそれを設定するinit方法です(私のシングルトンの方法で):

        NSString *mainPath = [[NSBundle mainBundle] bundlePath];
        NSString *levelConfigPlistLocation = [mainPath stringByAppendingPathComponent:@"levelconfig.plist"];
        NSDictionary *levelConfig = [[NSDictionary alloc] initWithContentsOfFile:levelConfigPlistLocation];
        completedLevels = [[NSMutableDictionary alloc]init];
        NSMutableDictionary *levelSets = [[NSMutableDictionary alloc]init];
        NSMutableDictionary *levels = [[NSMutableDictionary alloc]init];
        NSMutableDictionary *stats = [[NSMutableDictionary alloc]init];

        [stats setObject:[NSNumber numberWithBool:NO] forKey:@"levelDone"];
        [stats setObject:[NSNumber numberWithInt:0] forKey:@"stars"];
        [stats setObject:[NSNumber numberWithInt:0] forKey:@"time"];
        [stats setObject:[NSNumber numberWithInt:0] forKey:@"bestTime"];

        for (int i = 1; i<=18; i++) {
            [levels setObject:stats forKey:[NSString stringWithFormat:@"level%d", i]];
        }



        for(int i= 1; i<=15;i++){
        NSString *lvlSet = [NSString stringWithFormat:@"levelSet%d", i];
            [levelSets setObject:levels forKey:lvlSet];
        }


        NSArray *categoriesArray = [levelConfig objectForKey:@"categoriesArray"];

        for (int i=0; i<[categoriesArray count]; i++) {
            NSString *category = [[levelConfig objectForKey:@"categoriesArray"]objectAtIndex:i];
            [completedLevels setObject:levelSets forKey:category];
        }

私は自分の行動を説明したい:

私の意図は、次の形式で辞書を作成することでした。

     category =     {
        levelSet1 ={
              level1 ={
                 bestTime = 0;
                 levelDone = 0;
                 stars = 0;
                 time = 0;
                };
               level2={
                 bestTime = 0;
                 levelDone = 0;
                 stars = 0;
                 time = 0;
               };
              . 
              . 
              .
            }
          levelSet2 ={
              level1 ={
                 bestTime = 0;
                 levelDone = 0;
                 stars = 0;
                 time = 0;
                };
               level2={
                 bestTime = 0;
                 levelDone = 0;
                 stars = 0;
                 time = 0;
               };
              . 
              . 
              .
            }
         .
         . 
         .
       }

levelSet の場合の %d は、1 から 15 までの整数です。

レベルの場合の %d は、1 から 18 までの整数です。

いくつかのカテゴリがあるため、上記の例の複数のセットがあります。

これはうまく機能し、NSLog を呼び出すと、辞書がコンソールに表示されます。ただし、次の例に示すように、辞書のいくつかのエントリを変更したい場合に問題が発生します。

 NSString *category = [[GameStateSingleton sharedMySingleton]getCurrentCategory];
    NSString *levelSet = [NSString stringWithFormat:@"levelSet%d",[[GameStateSingleton sharedMySingleton]getSharedLevelSet]];
    NSNumber *currentLevel = [NSNumber numberWithInt:[[GameStateSingleton sharedMySingleton]getSharedLevel]];
    NSString *levelString = [NSString stringWithFormat:@"level%d", [currentLevel intValue]];

    NSMutableDictionary *categories = [[NSMutableDictionary alloc]initWithDictionary:
    [[GameStateSingleton sharedMySingleton]getCompletedLevels]];



    [[[[categories objectForKey:category]objectForKey:levelSet]objectForKey:levelString]setObject:[NSNumber numberWithBool:YES] forKey:@"levelDone"];

    [[GameStateSingleton sharedMySingleton]setCompletedLevels:categories];
    NSLog(@"%@",[[GameStateSingleton sharedMySingleton]getCompletedLevels]);

それを説明するには:

levelDoneプレイヤーがレベルを使い終わったら、エントリの値を変更したいと思います。しかし、後でログに記録すると、突然levelDone、すべてのカテゴリのすべてのエントリが BOOLEAN 値 1 に変わります。なぜですか?

- - - - - - - - - - アップデート - - - - - - - - - - - -

completedLevels = [[NSMutableDictionary alloc]init];
        NSMutableDictionary *levelSets = [[NSMutableDictionary alloc]init];
        NSMutableDictionary *levels = [[NSMutableDictionary alloc]init];
        NSMutableDictionary *stats = [[NSMutableDictionary alloc]init];

        [stats setObject:[NSNumber numberWithBool:NO] forKey:@"levelDone"];
        [stats setObject:[NSNumber numberWithInt:0] forKey:@"stars"];
        [stats setObject:[NSNumber numberWithInt:0] forKey:@"time"];
        [stats setObject:[NSNumber numberWithInt:0] forKey:@"bestTime"];

        for (int i = 1; i<=18; i++) {
            NSMutableDictionary *statsCopy = [stats mutableCopy];
            [levels setObject:statsCopy forKey:[NSString stringWithFormat:@"level%d", i]];
            [statsCopy release];
        }



        for(int i= 1; i<=15;i++){
            NSString *lvlSet = [NSString stringWithFormat:@"levelSet%d", i];
            NSMutableDictionary *levelsCopy = [levels mutableCopy];
            [levelSets setObject:levelsCopy forKey:lvlSet];
            [levelsCopy release];
        }


        NSArray *categoriesArray = [levelConfig objectForKey:@"categoriesArray"];

        for (int i=0; i<[categoriesArray count]; i++) {
            NSString *category = [[levelConfig objectForKey:@"categoriesArray"]objectAtIndex:i];
            NSMutableDictionary *levelSetsCopy = [levelSets mutableCopy];
            [completedLevels setObject:levelSetsCopy forKey:category];
            [levelSetsCopy release];

        }

取得して設定する部分は同じままでした...

__ _ __ _ _ __ _ __ _ __ ソリューション _ __ _ __ __ _ __ _ _ ____ _ _ _

NSMutableDictionary *mutableCopy = (NSMutableDictionary *)CFPropertyListCreateDeepCopy(kCFAllocatorDefault, (CFDictionaryRef)originalDictionary, kCFPropertyListMutableContainers);

この方法でディープコピーを作成しました。

4

1 に答える 1

5

基本的に、問題は、各レベルのレベル ディクショナリを同じ統計オブジェクトに設定していることです。

    for (int i = 1; i<=18; i++) {
        [levels setObject:stats forKey:[NSString stringWithFormat:@"level%d", i]];
    }

代わりに、それぞれをオブジェクトの異なる変更可能なコピーに設定する必要があります。

   for (int i = 1; i<=18; i++) {
        NSMutableDictionary *statsCopy = [stats mutableCopy];
        [levels setObject:statsCopy forKey:[NSString stringWithFormat:@"level%d", i]];
        [statsCopy release];
    }

これで最初の部分は解決するはずです。ただし、レベルセットにも同じ問題があります。基本的に、変更可能な辞書を追加するときはいつでも、同じ変更可能なオブジェクトを指そうとしているのか (同期を維持したいのか)、それともその変更可能なオブジェクトのコピーが必要なのか (したがって、それらは独立して動作する) を決定する必要があります。そして、この種のツリー構造の構築を検討する場合、これはすべてのレベルで検討する必要があることを意味します。

したがって、コードの残りの部分を見て、同じ方法でレベル セットとカテゴリを修正する必要があります。各ループ内で変更可能なコピーを作成し、元のオブジェクトを追加する代わりにその変更可能なコピーを追加します。また、辞書のコンテンツの内容を変更したいので、別の変更可能な辞書を含む変更可能なコピーを作成するたびに、そのコピーを各深さで作成する必要があります。

これらのものを深さ方向に構築するか、ディープコピーを行うかを選択する必要があります。別の質問があります: NSMutableDictionary のディープミュータブルコピーは、 ミュータブルディクショナリのディープコピーをかなりうまくカバーしています。または、構造の構築を逆にして、コピーを作成する代わりに、stats簡単にコピーできるものを除いて各辞書を構築することもできます。

ディープ コピーは、可変エントリのそれぞれのコピーを最も遠いリーフ ノードまで作成します。NSMutableDictionaries を、ツリーのベース (この場合は completedLevels) にあるツリーと考え、リーフをコピーする統計 NSMutableDictionaries の要素として考える場合、ツリーのすべての要素を個別に操作する必要があります。それは葉ノードまたは任意の中間です。

図は次のように作成できます。これは の内容を表していますMyDictionary

 Top-A:
        Second-A-1
        Second-A-2
 Top-B:
        Second-B-1
        Second-B-2

要約するMyDictionaryと、上部に があり、2 つのキー ( Top-ATop-B) があり、それぞれが個別の NSMutableDictionary オブジェクトに関連付けられています。これらの NSMutableDictionaries にはそれぞれ 2 つのキーがあり、それぞれが個別のオブジェクトに関連付けられています。

ofを作成する-mutableCopyMyDictionary、結果はNSMutableDictionary2 つのキー ( Top-ATop-B) を持つ新しいものになり、それぞれが NSMutableDictionary に関連付けられます。 ただし、これらのNSMutableDictionaryオブジェクトは、実際には のオブジェクトと同じですMyDictionary。これは浅いコピーです。つまり、新しいトップレベル オブジェクト ( の変更可能なコピーMyDictionary) がありますが、新しいディクショナリの各キーに関連付けられているオブジェクトは、 のキーに関連付けられていたオブジェクトと同じですMyDictionary。そのためTop-A、コピーを変更して別の に関連付けるとNSMutableDictionaryTop-AインMyDictionaryとコピーは同じではなくなります。ただし、 に関連付けられている値を変更すると、 と のコピーのSecond-A-1両方が変更されます。MyDictionaryMyDictionaryTop-A単一のオブジェクトを指しているからです。

ディープ コピーを作成すると、ユーティリティはすべてのディクショナリのすべての要素を個別にコピーします。つまり、 のコピーには、 に存在するものとMyDictionaryは別Top-Aの 、Second-A-1Second-A-2などがあるため、任意の値を変更できます。他のオブジェクトを変更することを恐れずに (どんなに深くても) 辞書のTop-BMyDictionary

于 2012-05-20T14:36:55.760 に答える