6

我有一个 UIPopoverController 存储在我的视图控制器的一个强属性中。当用户在弹出框可见时旋转 iPad 时,我关闭弹出框并将我的属性设置为 nil。

if (self.popover != nil) {
    [self.popover dismissPopoverAnimated:NO];
    self.popover.delegate = nil;
    self.popover = nil;
}

当代码达到 self.popover = nil 时,ARC 尝试解除 UIPopoverController 的分配,但它崩溃了,因为它应该仍然可见。

我应该如何在不崩溃的情况下解雇并消除弹出窗口?

4

3 回答 3

16

首先,建议检查是否正在显示弹出框,这也将方便地检查它是否已分配:

if ([self.popover isPopoverVisible]) {
    [self.popover dismissPopoverAnimated:NO];
}

现在,问题是,如果像这样以编程方式关闭弹出框,则不会获得委托回调- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController,但是您需要对弹出框的强引用,直到它不再可见。

这样做的方法是延迟将属性设置为 nil,直到您返回主运行循环,因为当您返回主运行循环时,所有动画都将完成,因此弹出框将不再可见。

您需要将设置 popover 为 nil 的代码移动到另一个方法中:

- (void)releasePopover {
    self.popover.delegate = nil;
    self.popover = nil;
}

然后,在您的旋转回调中,添加此方法以在主运行循环中触发,我喜欢通过向主运行循环添加调用操作来做到这一点:

if ([self.popover isPopoverVisible]){
    [self.popover dismissPopoverAnimated:NO];
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(releasePopover) object:nil];
    [[NSOperationQueue mainQueue] addOperation:invocationOperation];
}

最后,为了清洁起见,您可能希望-releasePopover从回调内部- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController调用。

所以,把它们放在一起:

- (void)releasePopover
{
    self.popover.delegate = nil;
    self.popover = nil;
}

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    if ([self.popover isPopoverVisible]){
        [self.popover dismissPopoverAnimated:NO];
        NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(releasePopover) object:nil];
        [[NSOperationQueue mainQueue] addOperation:invocationOperation];
    }
}

- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController
{
    [self releasePopover];
}

说了这么多,除非有充分的理由,否则您可能只想保留弹出框以重复使用,并且仅在收到内存不足警告和/或视图已卸载时将其设置为 nil,正如 Chris Loonam 的回答所提到的

于 2013-01-29T01:37:21.143 回答
1

如果您真的觉得有必要这样做,请尝试在 viewDidUnload 中将其清零。由于 ARC 自动释放对象,我不确定这样做是否真的有必要。

于 2013-01-27T21:31:39.350 回答
1

站在西蒙回答的肩膀上,这是我对崩溃的修复:

// set to nil on main queue to prevent "dealloc'd while still visible" exception
dispatch_async(dispatch_get_main_queue(), ^{
        self.popover = nil;
});
于 2013-02-26T18:24:49.280 回答