2011-06-26 44 views
2

Resold!被称为两次的Dealloc?

感谢Lone Gunman,这个问题是由于在发布它们之前没有将许多代表设置为零的疏忽。

这是一个奇怪的...我熟悉基本的内存管理,但我认为我看到的东西是不寻常的。这里是一个小背景...

我有一个NavigationController,处理以下ViewControllers之间导航:

首页 - >游戏 - >游戏

运行代码时离开时摔倒游戏。内GameViewController有一个类似于dealloc方法:

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

当导航控制器返回到游戏列表(从游戏中),它抛出一个EXC_BAD_ACCESS。所以我提出了我可靠的剖析器并检查僵尸。唉,就像我预料的那样,一条消息正在发送到一个释放对象!进一步挖掘我发现那里是在对象的历史记录3项:

  1. 局取得alloc'd(通过游戏的init方法调用)
  2. 局得到释放(通过游戏的dealloc方法调用)
  3. 局之中Zombie'd(由Game的dealloc方法调用)

这两个调用2和3都是从UINavigationController setDisappearingViewController中调用的。

在我的dealloc方法中,我为每个释放调用设置了断点,这时会发生[board release]调用,然后发生[opponentsViewController release]调用,然后再次发生[board release]调用。所以我看到dealloc方法没有完成并再次调用。

什么可能导致这种情况?

编辑:这是GameViewController Implementation

从游戏控制器代码,增加了本场比赛:

-(void) gotoGame:(int)tag { 

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

} 

编辑:这是GameViewController Header

+0

' - [NSObject dealloc]'不能执行两次。如果您在构建设置中启用“运行静态分析器”并尝试再次构建,您会遇到什么问题? – 2011-06-26 16:01:25

+0

当您多次调用发布时会发生这种情况。你能检查你没有在程序的其他任何地方发布主板吗?> – sumderungHAY

+0

@ WTP:没有来自静态分析器的投诉。 – Brent

回答

3

我会尝试所有的伊娃的代表设置为零(编辑:在的dealloc)的init方法。我有一个类似的问题与获取结果控制器。无法在dealloc中将其委托设置为零,并且核心数据堆栈在视图控制器发布时仍有指向它的指针。

所以,这是我的赌注,设置伊娃代表在dealloc中为零,但我看不到您的标题,以了解您遵守的协议是什么。

编辑:解释

设置一个委托实际上是给在执行该代表团的指针(我相信它通常是一个分配的属性)的对象。

@property (assign) delegate; 

我将使用我作为示例的问题。

假设你有一个视图控制器,它有一个fetchedResultsController作为ivar。当您设置FRC代理时:

fetchedResultsController.delegate = self; 

并且视图控制器被释放,任何使用该指针的对象仍然认为它是活的。你会想,既然FRC也是在dealloc中发布的,那么你会没事的(这就是为什么我花了4天时间才弄清楚:)),但是有时候实现的其他部分也会使用你的委托。所以修复是:

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

注意:只要新工具可用于所有人,您将不必担心这个东西了^^;

+1

这真是一个很好的观点。这里是标题,在这里有一批代表团......我想这是正确的方向。 – Brent

+0

修正了,谢谢!我希望有人能帮助填补我的知识空白。代表们做了什么让dealloc看起来像两次发射?他们的方法中的[super dealloc]调用是否会导致它再次触发? – Brent

+0

我为答案添加了一个解释。 –

-3

尝试

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

通过看起来你已经在头文件中声明了游戏的方式只是在推动你释放它之后,并且还用dealloc方法释放它。从dealloc方法中删除释放调用或者像这样改变你的方法。

-(void) gotoGame:(int)tag { 

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

} 

不使用标签的任何地方

也会更新。你为什么不创建一个这样

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

在发送释放(或任何其他方法)之前,检查是否有零是无用的。在nil上调用方法是一个noop。它什么也没做。因此你的建议也不会解决任何问题。 –

+0

@Johan Kool至少他的应用程序不会崩溃。 –

+3

你错过了这一点。发送'-release'消息给'nil'将不会**他的应用程序崩溃。而且,一个对象在被释放后不会自动成为“nil”(换句话说,“nil”不表示垃圾值)。所以检查是没用的。 ('-dealloc'实现中通常做的一件事是将指针清零,这可以防止崩溃,但它也可以隐藏错误)。 –