代码之家  ›  专栏  ›  技术社区  ›  SaltyNuts

在自定义UIViewController上调用[super dealloc]时,iPhone会出现错误访问

  •  3
  • SaltyNuts  · 技术社区  · 15 年前

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

    我的应用程序有一个分页的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的第1代ipodtouch上却始终如一。

    4 回复  |  直到 15 年前
        1
  •  6
  •   Chaythanya Nair    7 年前

    正在释放某些内容,但指针仍悬空。将NSZombieEnabled设置为YES,然后再次运行它。方法如下:

    • 产品->编辑方案
    • 添加到“要在环境中设置的变量”
      • 名称:NSZombieEnabled

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

    再次运行应用程序。在某个时刻,它会告诉您正在访问一个已经发布的对象。从这一点,你需要找出谁没有保留或谁是过度释放的对象。

    猎僵尸快乐。

        2
  •  1
  •   MWharton    14 年前

    UIBarButtonItem* timeLabel = [[UIBarButtonItem alloc] initWithTitle:@"time" style:UIBarButtonItemStylePlain target:nil action:nil];
    
    NSArray *items = [NSArray arrayWithObjects: timeLabel, nil];
    
    self.toolbarItems = items;
    

    接下来自然要做的是:

    [timeLabel release];
    

        3
  •  0
  •   tc.    15 年前

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

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

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

        4
  •  -1
  •   RupertP    15 年前

    不用替换数组中的元素,只需调用 removeObjectAtIndex: removeAllObjects: 以确保没有任何东西在不应该的地方保存引用。

    推荐文章