NSDictionary с целыми значениями

Я работаю над игрой с монстрами. Каждый из них имеет список статистических данных, которые все будут ints. Я могу настроить каждый stat как свою собственную переменную, но я бы предпочел сохранить их в NSDictionary, так как они все связаны. У меня возникает проблема, когда я пытаюсь изменить значение каждого стата.

Что у меня:

-(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;
}

Что я хочу сделать

-(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);
}

Ошибка, которую я получаю

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

Поэтому мне кажется очевидным, что причина, по которой я получаю проблему, заключается в том, что я получаю объект, возвращенный из objectForKey, вместо целого. Поэтому я попытался использовать метод intValue для объекта, который я получаю, но это дало мне еще одну ошибку, в частности:

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

У меня нет идей, как это исправить. Любая помощь? Было бы лучше просто отказаться от идеи сохранить их все вместе и просто использовать свойство int для каждого стата?

Ответы

Ответ 1

  1. Вы можете хранить только объекты, но не примитивы, в классах коллекции Cocoa, поэтому для хранения чисел необходимо использовать объекты NSNumber.
  2. Вам нужно использовать NSMutableDictionary если вы хотите изменить содержимое позже.
  3. Ваш вызов dictionaryWithObjectsAndKeys имеет обратные ключи и значения.
  4. Ваш объект stats не сохраняется, поэтому он будет освобожден в следующий раз во время цикла выполнения (если вы используете ручной подсчет ссылок, то есть).

Ты хочешь:

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];

Для того, чтобы изменить значения, вам нужно создать новый объект NSNumber как они неизменны, что-то вроде:

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

Все довольно утомительно, если вы спросите меня; должен быть более простой способ, например, как насчет создания класса Objective-C для хранения и манипулирования этим материалом?

Ответ 2

NSDictionary сохранить NSObject* s. Чтобы использовать их с целыми значениями, вам, к сожалению, нужно использовать что-то вроде NSNumber. Итак, ваша инициализация будет выглядеть так:

-(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;
}

Затем вам нужно будет найти их как числа:

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

ИЗМЕНИТЬ

Конечно, для этого self.stats должен быть NSMutableDictionary

Ответ 3

Адаптация ответа @trojanfoe для современного Objective-C с приятным синтаксическим сахаром:

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

И обновить значение:

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