3

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

我的应用程序有一个分页的 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 是一个包含 MyViewController 类型对象的 NSMutableArray。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

4 回答 4

6

正在释放某些东西,但指针仍然悬空。将 NSZombieEnabled 设置为 YES 并再次运行它。就是这样:

  • 产品 -> 编辑方案
  • 选择“参数”选项卡
  • 添加到“要在环境中设置的变量”
    • 名称:NSZombieEnabled
    • 值:是

在 Xcode 4.1 及更高版本中:

  • 产品 -> 编辑方案
  • 选择“诊断”选项卡
    • 您可以选择启用僵尸对象。

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

快乐的僵尸狩猎。

于 2010-08-06T18:45:52.340 回答
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,大概是因为视图控制器释放了数组和其中的所有项目。

于 2011-05-26T15:07:38.527 回答
0

默认情况下,视图控制器会在出现内存警告时自动卸载其视图,因此没有理由自行卸载控制器,除非它们包含大量开销。

视图控制器的视图是否仍在视图层次结构中?你可以用类似的东西来检查[viewController isViewLoaded] && viewController.view.superview。如果是这样,删除视图控制器可能不安全。

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

于 2010-08-06T19:11:31.393 回答
-1

而不是替换数组中的元素,您可以简单地调用removeObjectAtIndex:removeAllObjects:确保没有任何不应该持有的引用。

于 2010-08-06T18:57:04.307 回答