Ошибка памяти в Obj-C / Cocos2d, exc_bad_access при вызове свойства - PullRequest
3 голосов
/ 08 марта 2012

Я работаю над карточной игрой для iOS и столкнулся с проблемой управления памятью в Objective-C, которую я просто не могу понять.Я много раз читал об управлении памятью и думаю, что все делаю правильно, но всякий раз, когда я пытаюсь вызвать свойство из моего класса Card, игра вылетает.

Как это работаету меня есть NSMutableArray с именем deck, это свойство CCLayer, которое я использую в Cocos2d.Я выделяю и инициирую колоду в методе init слоя, а затем вызываю метод, который заполняет карты в колоде:

int i;
int j;
NSString *suit;

for (i = 0; i < 4; i++) {

    switch (i) {
        case 0:
            suit = @"Hearts";
            break;
        case 1:
            suit = @"Clubs";
            break;
        case 2:
            suit = @"Spades";
            break;
        case 3:
            suit = @"Diamonds";
            break;
    }


    for (j=1; j < 15; j++) {

        Card *card = [[Card alloc] init];
        card.suit = suit;
        card.rank = j;
        [card makeName];
        [deck addObject:card];

    }

}

В классе Card у меня есть свойства:

@property (nonatomic, retain) NSString *suit;
@property (nonatomic, retain) NSString *name;
@property (nonatomic) int rank;

Все они синтезированы, и я даже пытался выделить и инициировать каждый из них в методе инициализации карты (что, я думаю, мне не нужно, но все равно пытался).

Второй момент, когда я пытаюсь вызвать свойство карты, однако:

-(void) showCards: (NSMutableArray *) cards {

for (int i = 0; i < [cards count]; i++) {

    Card *card = [cards objectAtIndex:i];

    NSLog(@"%@",card.name);

}

}

Без кубиков.EXC_BAD_ACCESS.Я предполагаю, что карты каким-то образом освобождаются до того, как я их использую, но я сделал все, чтобы держать их рядом, о чем я могу думать.Какие-нибудь мысли?Я предполагаю, что это что-то простое, что я неправильно понял, но у меня нет идей.Спасибо!

Редактировать: Добавлено по запросу:

Объявление класса:

@interface Card : NSObject {

//NSString *suit;
//int rank;
//NSString *name;

}

property (nonatomic, retain) NSString *suit;
property (nonatomic, retain) NSString *name;
property (nonatomic) int rank;'

метод init (на данный момент - просто добавьте alloc / init, чтобы увидеть, будет ли онработа):

-(id) init {
self = [super init];
if (self) {

    suit = [NSString new];
    rank = 0;
    name = [NSString new];

}
return self;
}

Вот makeName:

-(void) makeName {

NSString *rankString;

switch (rank) {
case 1:
        rankString = @"One";
        break;
    case 2:
        rankString = @"Two";
        break;
    case 3:
        rankString = @"Three";
        break;
    case 4:
        rankString = @"Four";
        break;
    case 5:
        rankString = @"Five";
        break;
    case 6:
        rankString = @"Six";
        break;
    case 7:
        rankString = @"Seven";
        break;
    case 8:
        rankString = @"Eight";
        break;

    case 9:
        rankString = @"Nine";
        break;
    case 10:
        rankString = @"Ten";
        break;
    case 11:
        rankString = @"Jack";
        break;
    case 12:
        rankString = @"Queen";
        break;
    case 13:
        rankString = @"King";
        break;
    case 14:
        rankString = @"Ace";
        break;
}

NSString *cardName = [NSString stringWithFormat:@"%@ of %@", rankString, self.suit];

name = cardName;

}

1 Ответ

3 голосов
/ 08 марта 2012

Я думаю, вы немного перепутали свойства и переменные экземпляра. Переменные экземпляра - это то, что ссылается на объекты, а свойства - это просто причудливый способ присваивать им и получать их.

Где у вас есть:

name = cardName;

Что это делает, так это присвоение переменной экземпляра с именем name. Это не присвоение свойству - это делается с помощью синтаксиса с точкой - self.name = cardName. Что произойдет с кодом в его нынешнем виде, так это то, что вы потеряете ссылку на любой существующий объект, который у вас есть в переменной экземпляра - таким образом, происходит утечка памяти - и ссылка на новый объект будет помещена на место. Но если вы посмотрите, откуда приходит новый объект:

NSString *cardName = [NSString stringWithFormat:...

... вы увидите, что он выпущен автоматически. Таким образом, ничто не удерживает объект, и он будет освобожден в какой-то момент в будущем. У вас по-прежнему будет ссылка на ячейку памяти, но она не будет содержать объект, который вам нужен - это висячий указатель и вероятная причина вашего сбоя.

Теперь, если мы перейдем к использованию точечного синтаксиса:

self.name = cardName;

... то, что здесь происходит, эквивалентно [self setName:cardName]; Это метод, который вы сгенерировали с помощью @synthesize. Этот метод автоматически освобождает объект, который вы в данный момент храните в переменной экземпляра, и сохраняет новый объект, потому что вы объявили свойство retain.

...