【问题标题】:Memory Crash in UIPopoverControllerUIPopoverController 中的内存崩溃
【发布时间】:2011-09-25 21:29:10
【问题描述】:

我现在已经花了几天时间试图弄清楚发生了什么,而且我这辈子看不到自己做错了什么。当用户触摸屏幕上的一个点时,我会弹出一个 UIPopover。弹出框有一个选项卡控制器和表格视图,用于显示有关该点的信息。但是当弹出窗口被解除时,它会崩溃并声称: -[UIAnimator removeAnimationsForTarget:]: 消息发送到释放的实例

这是加载视图控制器的代码:

MyViewController *popView = [[MyViewController alloc] init];
myPop = [[UIPopoverController alloc] initWithContentViewController:pop];
[popView release];
myPop.delegate = self;
[airportPop setPopoverContentSize:popView.view.frame.size];
[airportPop presentPopoverFromRect:CGRectMake(location.x,location.y,1,1) inView:self.mainView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

- (void)dismissPopover {
    if( myPop != nil ) {
        [myPop dismissPopoverAnimated:YES];
        [myPop.delegate popoverControllerDidDismissPopover:airportPop];
    }
}

- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
    [myPop release];
    myPop = nil;
}

实际的 MyViewController 只是一个带有(为简洁起见)init 的 UIViewController:

  - (id)init
{
    self = [super init];
    //create a newview 
    self.view = popView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, POPUP_WIDTH, POPUP_HEIGHT)];
    [popView release];

    topBar = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, POPUP_WIDTH, 30)];
             ....
    [popView addSubview:topBar];
    [topBar release];

    //create a table view 
    self.table = [[UITableView alloc] initWithFrame:CGRectMake(0, 30, POPUP_WIDTH, POPUP_HEIGHT-30-49)];
        table.delegate = table.dataSource = self;
         ....

    //create a tab bar 
    tabBar = [[UITabBar alloc] initWithFrame:CGRectMake(0, POPUP_HEIGHT-49, POPUP_WIDTH, 49)];
    tabBar.delegate = self;

    [popView addSubview:tabBar];
    [popView addSubview:table];

    [tabBar release];
    [table release];
    return( self );
}

Dealloc 只不过是 [super dealloc],因为一切本质上都归视图所有,视图控制器会处理它。当 myPop 被释放时,在 DidDismissPopover 中,视图也被释放,所以这似乎工作正常。但不久之后,我遇到了崩溃。

当弹出窗口消失时,我需要做一些特殊的事情来丢弃标签视图或表格视图吗?

我正在对表格中的单元格使用自动释放,我应该停止这样做吗?

        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];

提前感谢您的帮助!!!任何想法都非常感谢!

-凯文

【问题讨论】:

    标签: objective-c ios ipad memory-management uipopover


    【解决方案1】:

    [myPop dismissPopoverAnimated:YES] 将在方法调用之后继续访问您的对象,因为您为动画设置了 YES(有一个计时器和其他东西在后台执行动画)

    因此,您可以将其标记为 autorelease 以推迟此操作,而不是立即释放该对象,这实际上可能会解决它,也可能不会。

    或者将发布推迟到某个时间之后,您可以确定动画将会完成。您可以为此使用 GCD(如果您使用的是 iOS 4+),并且 UIKit 中动画的默认时间是 0.3 秒,下面的代码应该可以解决问题。

    double delayInSeconds = 0.3;
    dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
    dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
        [myPop.delegate popoverControllerDidDismissPopover:airportPop];
    });
    

    编辑:您应该仅将这段时间用于测试建议,因为它远不是释放对象的正确方法。

    您应该存储一个指向您的UIPopover 的指针并将其释放到您的类dealloc 方法中。

    【讨论】:

    • 是的 - 就是这样...将 Animated 设置为 NO 似乎可以完全解决崩溃问题。 (使用 autorelease 没有。)所以,这是有道理的,但是如何知道何时保存以释放弹出框?
    • 顺便说一句,0.3 秒没有用。我继续将它设置为 5,从那以后它就没有崩溃过。
    【解决方案2】:

    在你的可执行文件信息->参数选项卡->环境变量中添加以下键

    NSZombieEnabled = YES
    
    CFZombie = 5
    
    MallocStackLoggingNoCompact = 1
    

    然后当您自动崩溃时,您会收到一条消息 像这样的东西

    (gdb) 继续

    2011-06-09 11:46:08.404 测试 [6842:40b] * -[_NSArrayI release]:消息发送到释放的实例 0X64a4900

    然后输入

    (gdb) info malloc-history 0x64a4900

    它将为您提供完整的历史记录。

    也许它可以帮助你找到那个地方。

    你也可以在崩溃时使用 where 命令。

    【讨论】:

    • 这就是我知道它在 UIAnimator 中的方式。每次调用的“已发布类”都不同,但通常在崩溃时尝试访问表格或选项卡视图。
    • 有没有办法在lldb中使用这个调试工具?
    【解决方案3】:

    避免等待动画结束的最快方法是在您关闭弹出窗口或 Popover Delegate 方法时设置popoverController.delegate = nil

    - (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
    

    被调用。

    【讨论】:

    • 这不适用于以编程方式关闭的弹出框。从 Apple 方面来说,不提供完整的回调或调用“didDismissPopover”是非常愚蠢的。
    猜你喜欢
    • 1970-01-01
    • 2012-06-13
    • 1970-01-01
    • 1970-01-01
    • 2012-01-28
    • 2012-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多