Obj-C / Cocos2d memory error, exc_bad_access when calling property

I'm working on a card game for iOS and I'm running into what I'm guessing is a memory management problem in Objective-C that I just can't figure out. I have read about memory management many times and I think I am doing everything right, but whenever I try to call a property from the Card class, I get the game crashing.

The way it works is I have an NSMutableArray called deck, which is a CCLayer property that I am using in Cocos2d. I select and initialize the deck in the init method of this layer, and then call the method that fills the cards in the deck:

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

    }

}

      

In the Card class, I have properties:

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

      

Each of them is synthesized, and I even tried to isolate and initiate each one in the card initialization method (which I don't think I need to do, but tried anyway).

Second, I am trying to call the Card property, however:

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

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

    Card *card = [cards objectAtIndex:i];

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

}

      

}

No cubes. EXC_BAD_ACCESS. I am assuming the cards are cleared somehow before I use them, but I did everything to keep them around that I can think of. Any thoughts? I am guessing this is something simple that I have misunderstood, but I have no idea. Thank!

Edit: Added as requested:

Class declaration:

@interface Card : NSObject {

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

}

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

      

init method (for now - just added alloc / init to see if it works):

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

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

}
return self;
}

      

Here's the 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;

}

      

+3


source to share


1 answer


I think you got a bit confused between properties and instance variables. Instance variables are what referenced objects, and properties are just a fancy way of assigning and getting them.

Where do you have:

name = cardName;

      

What this does is assignment to an instance variable called name

. It does not assign a property - this is done using the dot syntax - self.name = cardName

. What will happen to the code as it stands is that you will lose a reference to any existing object you have in an instance variable - thus a memory leak - and a reference to the new object will be put in place. But if you look at where the new object comes from:

NSString *cardName = [NSString stringWithFormat:...

      



... you will see that it is auto-implemented. This way, nothing will survive and at some point in the future it will be released. You will still have a memory location reference, but it will not contain the object you want - this is a dangling pointer and the likely reason for your crash.

Now, if we move on to using the dot syntax:

self.name = cardName;

      

... what happens here is equivalent to [self setName:cardName];

This is the method you created with @synthesize

. This method will automatically free the object you are currently storing in an instance variable and store the new object because you declared a property retain

.

+3


source







All Articles