web-dev-qa-db-fra.com

NSDictionary avec des valeurs entières

Je travaille sur un jeu avec des monstres. Chacun a une liste de statistiques qui seront toutes des ints. Je peux configurer chaque statistique comme sa propre variable, mais je préfère les conserver dans un NSDictionary car elles sont toutes liées. Je rencontre un problème lorsque j'essaie de changer la valeur de chaque statistique.

Ce que j'ai:

-(id) init {
    self = [super init];
    if(self) {
        stats = [NSDictionary dictionaryWithObjectsAndKeys:
              @"Attack",  0,
              @"Defense", 0,
              @"Special Attack", 0,
              @"Special Defense", 0,
              @"HP", 0, nil];
    }
    return self;
}

Ce que je veux faire

-(void) levelUp {
    self.level++;
    [self.stats objectForKey:@"Attack"] += (level * 5);
    [self.stats objectForKey:@"Defense"] += (level * 5);
    [self.stats objectForKey:@"Special Attack"] += (level * 5);
    [self.stats objectForKey:@"Special Defense"] += (level * 5);
    [self.stats objectForKey:@"HP"] += (level * 5);
}

Erreur que j'obtiens

Arithmetic on pointer to interface 'id', which is not a constant size in non-fragile ABI

Il me semble donc évident que la raison pour laquelle je rencontre le problème est que je reçois un objet renvoyé par objectForKey au lieu d'un entier. J'ai donc essayé de faire la méthode intValue sur l'objet que je reçois, mais cela m'a donné une autre erreur, en particulier:

Assigning to 'readonly' return result of an objective-c message not allowed

Je n'ai plus d'idées pour résoudre ce problème. De l'aide? Serait-il préférable de renoncer à l'idée de les stocker tous ensemble et d'utiliser simplement une propriété int pour chaque statistique?

19
CaldwellYSR
  1. Vous ne pouvez stocker des objets, pas des primitives, dans les classes de collection Cocoa, donc pour stocker des nombres, vous devez utiliser des objets NSNumber.
  2. Vous devez utiliser un NSMutableDictionary si vous souhaitez modifier le contenu ultérieurement.
  3. Votre appel à dictionaryWithObjectsAndKeys a les clés et les valeurs inversées.
  4. Votre objet stats n'est pas conservé, il sera donc libéré la prochaine fois dans la boucle d'exécution (si vous utilisez le comptage manuel des références, c'est-à-dire).

Tu veux:

stats = [[NSMutableDictionary dictionaryWithObjectsAndKeys:
    [NSNumber numberWithInt:0], @"Attack",
    [NSNumber numberWithInt:0], @"Defense",
    [NSNumber numberWithInt:0], @"Special Attack",
    [NSNumber numberWithInt:0], @"Special Defense",
    [NSNumber numberWithInt:0], @"HP",
    nil] retain];

Afin de modifier les valeurs, vous devez créer un nouvel objet NSNumber car elles sont immuables, donc quelque chose comme:

NSNumber *num = [stats objectForKey:@"Attack"];
NSNumber *newNum = [NSNumber numberWithInt:[num intValue] + (level * 5)];
[stats setObject:newNum forKey:@"Attack"];

Tout cela est assez fastidieux si vous me demandez; il doit y avoir un moyen plus simple, par exemple que diriez-vous de créer une classe Objective-C pour stocker et manipuler ce genre de choses?

57
trojanfoe

NSDictionarys store NSObject*s. Pour les utiliser avec des valeurs entières, vous devez malheureusement utiliser quelque chose comme NSNumber. Ainsi, votre initialisation ressemblerait à:

-(id) init {
    self = [super init];
    if(self) {
        stats = [NSDictionary dictionaryWithObjectsAndKeys:
              @"Attack",  [NSNumber numberWithInt:0],
              @"Defense", [NSNumber numberWithInt:0],
              @"Special Attack", [NSNumber numberWithInt:0],
              @"Special Defense", [NSNumber numberWithInt:0],
              @"HP", [NSNumber numberWithInt:0], nil];
    }
    return self;
}

Il vous faudrait ensuite les récupérer sous forme de nombres:

NSNumber *atk = [self.stats objectForKey:@"Attack"];
int iAtk = [atk intValue];
[self.stats setObject:[NSNumber numberWithInt:iAtk] forKey:@"Attack"];

MODIFIER

Bien sûr, pour ce faire, self.stats doit être un NSMutableDictionary

7
Dan F

Adapter la réponse de @ trojanfoe à l'Objective-C moderne avec du sucre de syntaxe Nice:

stats = [@{@"Attack"          : @0,
           @"Defense"         : @0,
           @"Special Attack"  : @0,
           @"Special Defense" : @0,
           @"HP"              : @0} mutableCopy];

Et pour mettre à jour une valeur:

stats[@"Attack"] = @([stats[@"Attack"] intValue] + (level * 5));
6
TalkLittle