views:

116

answers:

5

I have a method to generate a Deck object (NSObject subclass with an NSMutableArray property) and it populates the array with Card objects (UIView subclass with some integer and one NSString property). When I ask for a Deck I check to see if one already exists (I think) and if so, release it before getting a new one.

The code from my viewcontroller...

#import "FlashTestViewController.h"

@implementation FlashTestViewController

- (IBAction)generateDeck {

    if (aDeck != nil) {
        [aDeck release];
    }

    aDeck = [[Deck alloc] initDeckWithOperator:@"+"];
}


- (IBAction)generateCard {

    if (aCard != nil) {
        [aCard fadeAway];
    }

    aCard = [aDeck newCardFromDeck];
    [self.view addSubview:aCard];
}

- (void)fadeAway {
    [aCard removeFromSuperview];
    [aCard release];
    }

    @end

The Deck class is as follows...

#import <Foundation/Foundation.h>
#import "Card.h"

@class Deck;

@interface Deck : NSObject {

    NSMutableArray* cards;
}

@property(nonatomic, retain) NSMutableArray* cards;

- (id)initDeckWithOperator: (NSString*)mathOper;
- (id)newCardFromDeck;

@end

- (id)initDeckWithOperator: (NSString*)mathOper {

    if (cards != nil) {
        [cards release];
    }
    cards = [[NSMutableArray alloc] init];
    for (int i=0; i<11; i++) {
        for (int j=0; j<11; j++) {
            int xPos = (random() % 220) + 10;
            int yPos = (random() % 360) + 10;
            Card* aCard = [[Card alloc] initWithFrame:CGRectMake(xPos, yPos, 60, 80)];
            aCard.upperOperand = i;
            aCard.lowerOperand = j;
            aCard.theOperator = mathOper;
            aCard.theResult = i + j;

            UITextView* upperTextView = [[UITextView alloc] initWithFrame:CGRectMake(5, 5, 50, 20)];
        NSString* upperOper = [[NSString alloc] initWithFormat:@"     %d", i];
        upperTextView.text = upperOper;
        [aCard addSubview:upperTextView];
        [upperTextView release];
        [upperOper release];

        UITextView* middleTextView = [[UITextView alloc] initWithFrame:CGRectMake(5, 30, 50, 20)];
        NSString* middleOper = [[NSString alloc] initWithFormat:@"%@  %d", mathOper, j];
        middleTextView.text = middleOper;
        [aCard addSubview:middleTextView];
        [middleTextView release];
        [middleOper release];

        UITextView* lowerTextView = [[UITextView alloc] initWithFrame:CGRectMake(5, 55, 50, 20)];
        NSString* lowerOper = [[NSString alloc] initWithFormat:@"     %d", j+i];
            lowerTextView.text = lowerOper;
            [aCard addSubview:lowerTextView];
            [lowerTextView release];
            [lowerOper release];

            [cards addObject: aCard];
            [aCard release];
        }
    }
    return self;
}

- (id)newCardFromDeck {
    int index = random() % [cards count];
    Card* selectedCard = [[cards objectAtIndex:index] retain];
    [cards removeObjectAtIndex:index];
    return selectedCard;
}

@end

I do the same thing when I ask for a new card from the newCardFromDeck method and it works. Any suggestions?

Thanks!

+2  A: 

Looking at this line of code:

cards = [[NSMutableArray alloc] init];

Do you release cards in your dealloc method? It looks like this could potentially be a memory leak.

mipadi
I guess I don't understand exactly when dealloc for a particular class gets called. I don't call it anywhere explicitly - in fact I didn't even have a dealloc method as I subclassed NSObject and didn't add it.
Steve
You should make one. `dealloc` is called when your object is released. You (should) never call it directly, but the Cocoa framework will do so.
mipadi
It's more accurate to say it's called when the object is released and there's no object left retaining it.
Chuck
A: 

Are you releasing 'cards'?

Griffo
+2  A: 

Add this code to your Deck.m file:

- (void)dealloc
{
    [cards release];
    [super dealloc];
}
BP
I subclassed NSObject (for the first time) and I'm used to getting dealloc automatically, which reminds me to release stuff there.I get the memory leak each time I generate a new Deck though. Would the release I do at the beginning get rid of the old cards array? And in the controller method, I check for an existing instance of Deck and if there is one, release it there. At least that what I think I'm doing.
Steve
When you create a new Deck, you automatically get a new cards array. Everything else that I can see going on (including releasing the Deck in your view controller) looks good, the dealloc override in your Deck object gets called when you release the deck object from your view controller. Don't forget the super, just to make sure anything else you are subclassing also has a chance to release.
BP
A: 

aDeck in generateDeck is also be a leak if you don't release it in the view's dealloc.

rchern
A: 

In newCardFromDeck:

Card* selectedCard = [[cards objectAtIndex:index] retain];

looks like you retain the card and return it somewhere. Where does this return value end up? If it ends up in another variable with a 'retain' property on it, it can get retained a second time (upon assignment to the variable).

5ound