释放包含滚动UITableView的视图控制器时,Iphone App崩溃

时间:2011-02-17 01:21:36

标签: iphone uitableview crash scroll quartz-graphics

这是一个非常非常奇怪的错误。很难描述我所拥有的确切项目,但我会尝试创建一个更简单的表示我所拥有的类。它是这样的:

假设我有一个导航控制器作为我的顶视图控制器。在其中,我有一个UIViewController,让我们说一个ContactsScreenController。这个视图包含多个UITableView,每个UITableView都由MyTableController类型的单独对象(delegate& datasource)控制。我通过保留一组控制器

来做到这一点

// This is the interface for my screen controller. An object of this type goes in a top-
// level navigation controller
// MainScreenController.h
@interface ContactsScreenController : UIViewController

    NSMutableArray* tableControllers;

@end



// MainScreenController.m

- (UITableViewCell*)cellForRowAtIndexPath..something..
{
    // Here what I do is create a new controller if needed, and add it to tableControllers
    // Memory allocations & releases are good because I checked with instruments
}

#define SAFE_DEL(x)   { if (x != nil) { [x release]; x = nil; } }

- (void)dealloc
{
    SAFE_DEL(tableControllers);
    [super dealloc];
}

现在,MyTableController是一个更复杂的对象,因为它处理从Web服务获取数据,但基本上我要做的是确保在删除对象时,我取消任何待处理的数据请求,如下所示: / p>


// MyTableController.m
- (void)dealloc
{
    [globalDataProvider cancelRequestsForController:self];

    // release other objects i might have
    [super dealloc];
}

好的,这是我的对象设置。当我删除对象tableControllers时发生崩溃。它减少了我的MyTableController对象的retainCount,它达到0(使用Instruments检查)。但是对于一些UNKNOWN的原因,我得到了cancelRequestsForController的调用,保留计数为零之后。 显然,我得到了一个EXC_BAD_ACCESS。

在您开始认为我的保留/释放对存在问题之前,如果我在内部表静态时释放主屏幕控制器,应用程序将完美运行。一旦滚动,我点击导航控制器中的后退按钮,我就会遇到错误。

我已经使用仪器检查了内部控制器的保留计数变化的整个历史记录,这很好(没有不寻常的东西)。当错误发生时,我在历史记录中的最后一个条目来自QuartzCore run_animation_callbacks,保留计数为-1。

有什么想法吗? :)

PS:作为一个快速解决方案,我已经在一个单独的方法中移动了cancelRequestsForController,我在发布之前为tableControllers中的每个对象手动调用它。这样我就确定在发布后不会有任何调用,无论tableview的状态如何。


- (void)dealloc
{
    for (TableController* c in tableControllers)
        [c cancelRequests];
    SAFE_DEL(tableControllers);
    [super dealloc];
}

但我出于几个原因不喜欢这个解决方案。

3 个答案:

答案 0 :(得分:2)

感谢大家的回答/评论 在我有机会释放我的对象之前,通过调用对象中的[super dealloc]来生成问题。这导致了很多疯狂的事情发生。我在我的dealloc方法结束时移动了[super dealloc](在我发布之后),现在它运行正常。

答案 1 :(得分:1)

SAFE_DEL宏是不必要的,并且使代码的可读性降低。只需:

[someObject release], someObject = nil;

如果someObject已经为零并且它使代码更直接可读,那将无关紧要。

  

一旦滚动,我就会击中   导航中的后退按钮   控制器我遇到了错误。

任何时候你有非内存管理逻辑,你都有脆弱性。也就是说,当执行dealloc时,很可能是因为应用程序中有一个完整的对象子图正在被释放。由于解除分配顺序在很大程度上是不确定的,因此您无法安全地触发dealloc中的任何复杂行为,而不会有发送已发送dealloc对象的风险。< / p>

最好的解决方案是dealloc 中获取取消机制!

答案 2 :(得分:0)

要检查两件事:  1.你的globalDataProvider(或任何其他类)是否有对你的控制器的引用(即用数据回调它?)你的保留计数可能为零但是由于错误的原因。你是如何分配阵列的,以及阵列中的每个控制器?你有@properties吗?  2.在您的可执行文件属性Arguements屏幕中,设置NSZombieEnabled = YES这将告诉您在保留计数为零时确切调用哪个对象。 HTH, -Mike