在自定义UIViewController上调用[super dealloc]时的iPhone EXC_BAD_ACCESS

时间:2010-08-06 18:38:52

标签: iphone dealloc

我不知所措!这是仅在特定条件下发生的那些讨厌的错误之一,但我无法直接链接条件和结果。

我的应用程序有一个分页的UIScrollView,其中每个页面的视图来自一个MyViewController,一个UITableViewController的子类。为了最小化内存使用量,我卸载那些当前不可见的控制器。这是我的“清洁”方法:

- (void) cleanViewControllers:(BOOL)all {

    if (all) { 
    // called if some major changes occurred and ALL controllers need to be cleared

        for (NSInteger i = 0; i < [viewControllers count]; i++)
            [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
    }
    else if ([viewControllers count] > 2) {
    // called if only the nearest, no longer visible controller need to be cleared
        NSInteger i = pageControl.currentPage - 2;
        if (i > -1) [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
        i = pageControl.currentPage + 2;
        if (i < [viewControllers count]) [viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];
    }
}

这条线崩溃了应用程序:

viewControllers replaceObjectAtIndex:i withObject:[NSNull null]];

viewControllers是一个NSMutableArray,包含MyViewController类型的对象。 MyViewController没有自定义属性,其dealloc方法只包含[super dealloc]调用。

这是调试器显示的内容: alt text http://a.imageshack.us/img831/3610/screenshot20100806at126.png

事情是,每次清除控制器时都不会发生这种情况,但有时只会发生。具体来说,在某些更改触发完全清理并重新绘制ScrollView后,它会显示当前页面(称为X),但是只要我滚动到足以导致X的清理,就会发生此崩溃。这让我疯了!

另一件事,这不会发生在4.0模拟器中,也不会发生在iPad上,而是在运行3.1.3的第一代iPod touch上非常一致。

4 个答案:

答案 0 :(得分:6)

有些东西正在被释放,但指针仍悬空。将NSZombieEnabled设置为YES并再次运行它。方法如下:

  • 产品 - &gt;编辑方案
  • 选择“参数”标签
  • 添加到“要在环境中设置的变量”
    • 姓名:NSZombieEnabled
    • 价值:是

在Xcode 4.1及以上版本中:

  • 产品 - &gt;编辑方案
  • 选择“诊断”标签
    • 您可以选择启用僵尸对象。

再次运行该应用。在某些时候它会告诉你你正在访问已经发布的对象。从那里你需要弄清楚谁不保留或谁过度释放对象。

快乐的僵尸狩猎。

答案 1 :(得分:1)

通常这可以通过分配一些内容然后将其设置为ViewController中的内容然后释放它来引起,例如:

UIBarButtonItem* timeLabel = [[UIBarButtonItem alloc] initWithTitle:@"time" style:UIBarButtonItemStylePlain target:nil action:nil];

NSArray *items = [NSArray arrayWithObjects: timeLabel, nil];

self.toolbarItems = items;

现在自然要做的就是:

[timeLabel release];

但这会导致[super dealloc]上的EXC_BAD_ACCESS,大概是因为视图控制器释放了数组及其中的所有项目。

答案 2 :(得分:0)

默认情况下,View控制器会自动卸载内存警告上的视图,因此除非它们包含大量开销,否则没有理由自行卸载控制器。

视图控制器的视图是否仍在视图层次结构中?您可以查看[viewController isViewLoaded] && viewController.view.superview之类的内容。如果是这样,删除视图控制器可能不安全。

(注意isViewLoaded检查,因为如果视图尚未加载,UIViewController.view将加载视图。)

答案 3 :(得分:-1)

您可以简单地调用removeObjectAtIndex:removeAllObjects:,而不是替换数组中的元素,以确保没有任何内容可以保留参考。