2
votes

Resloved!

Thanks to Lone Gunman, this issue was due to an oversight of not setting the many delegates to nil before releasing them.

This is a strange one... I'm familiar with basic memory management but I think something is unusual about what I am seeing. Here is a little background...

I have a NavigationController that handles the navigation between the following ViewControllers:

Home -> Games -> Game

When running the code it falls down when leaving the Game. Within the GameViewController there is a dealloc method that resembles:

- (void)dealloc 
{
    [board release];
    [opponentsViewController release];
    [instructionsViewController release];
    [imgPicker release];
    [gameView release];
    [super dealloc];
}

When the navigation controller goes back to the Games list (from the Game) it throws a EXC_BAD_ACCESS. So I bring up my trusty profiler and check for Zombies. Alas, just as I expected a message is being sent to a deallocated object! Digging deeper I find there to be 3 entries in the object's history:

  1. Board getting alloc'd (called by Game's init method)
  2. Board getting released (called by Game's dealloc method)
  3. Board being Zombie'd (called by Game's dealloc method)

Both calls 2 and 3 are called from UINavigationController setDisappearingViewController.

In my dealloc method I set breakpoints to each release call, when doing so - the [board release] call occurs, then the [opponentsViewController release] call occurs then the [board release] call occurs again. So I'm seeing the dealloc method does not finish completely and calls again.

What might be causing this?

Edit: This is the GameViewController Implementation

Code from the Games controller that adds this game:

-(void) gotoGame:(int)tag {

    game = [[GameViewController alloc] init];
    [self.navigationController pushViewController:game animated:YES];
    [game release];

}

Edit: This is the GameViewController Header

2
-[NSObject dealloc] cannot be executed twice. If you enable 'Run Static Analyser' in the build settings and try to build again, what issues do you get?user142019
This happens when you are calling release too many times. Can you check you are not releasing Board anywhere else in the program WITHOUT retaining it?>sumderungHAY
@ WTP: No complaints from the static analyzer.Brent
How many times do you release and retain board?user142019
Edit: Added implementation file for GameViewControllerBrent

2 Answers

3
votes

I would try setting all your ivar's delegates to nil (EDIT: in dealloc). I've had a similar problem with a fetched results controller. Failed to set the its delegate to nil in dealloc and the core data stack still had a pointer to it when the view controller was released.

So that's my bet, set ivar delegates to nil in dealloc, although I can't see your header to know what protocols your are conforming to be sure.

EDIT: Explanation

Setting a delegate is actually giving the object that is doing the delegation a pointer (I believe it usually an assigned property).

@property (assign) delegate;

I'll use the problem I had as an example.

So let's say you have a view controller that has a fetchedResultsController as an ivar. When you set the FRCs delegate:

fetchedResultsController.delegate = self;

and the view controller gets released, any object that is using that pointer still thinks it's live. You would think since the FRC is getting released in dealloc as well, you'd be fine(which is why it took me 4 days to figure this out :) ), but sometimes other parts of an implementation use your delegate as well. So the fix is:

-(void)dealloc
{
    self.fetchedResultsController.delegate = nil;
    [_fetchedResultsController release];
    [super dealloc];
}

Note: as soon as the new tools are available to everyone you won't have to worry about this stuff anymore ^ ^;

-3
votes

try

- (void) dealloc {
    if(game != nil){
     //release here
     [game release];
    }
    [super dealloc];
  }

By the way it seems you have declare game in header file and just after pushing you are releasing it and also in dealloc method you are releasing it. Either remove the release call from dealloc method or change you method like this.

-(void) gotoGame:(int)tag {

    GameViewController *game = [[GameViewController alloc] init];
    [self.navigationController pushViewController:game animated:YES];
    [game release];

}

UPDATE

Also you are not using the tag anywhere. Why don't you create your init method like this

GameViewController *game = [[GameViewController alloc] initWithTag:tag];
[self.navigationController pushViewController:game animated:YES];
[game release];