UIDocumentInteractionController的奇怪问题

时间:2010-05-26 07:11:44

标签: iphone ipad document

我不知道这段代码有什么问题,但每当我运行应用程序时,在显示菜单后,应用程序崩溃。

NSString * path = [[NSBundle mainBundle] pathForResource:@"tung" ofType:@"doc"];

UIDocumentInteractionController *docController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];

docController.delegate = self;

//[docController presentPreviewAnimated:YES];

CGRect rect = CGRectMake(0, 0, 300, 300);
[docController presentOptionsMenuFromRect:rect inView:self.view animated:YES];

我得到的错误:

  

***因未捕获的异常'NSGenericException'而终止应用,   原因:' - [UIPopoverController   当popover到达时达到了dealloc   仍然可见。'

我现在该怎么办?

6 个答案:

答案 0 :(得分:23)

要通过“一次性”UIDocumentInteractionController预览文档,您应该在interactionControllerWithURL之后保留它,并在UIDocumentInteractionControllerDelegate方法documentInteractionControllerDidDismissOptionsMenu中自动释放它。正如David Liu所说,释放它会崩溃。但是自动释放工作。我已经检查过dealloc实际上是被调用的。

以下代码应该有效:


- (void)previewDocumentWithURL:(NSURL*)url
{
    UIDocumentInteractionController* preview = [UIDocumentInteractionController interactionControllerWithURL:url];
    preview.delegate = self;
    [preview presentPreviewAnimated:YES];
    [preview retain];
}
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
{
    [controller autorelease];
}

答案 1 :(得分:8)

这基本上是旧的内存管理问题。

[UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]]返回一个自动释放的对象,因此在代码块完成后很快就会自动释放。我猜这与presentModalViewController不同,它会为你保留一份副本,但这是一个侧面点。

基本上,您需要在代码块结束之前保留它。更烦人的部分是跟踪docController正在做什么,所以你不会泄漏内存。你必须检查结果 [docController presentOptionsMenuFromRect:rect inView:self.view animated:YES];

如果它返回NO,则表示菜单从未显示过,因此您应该立即对其进行释放(如果您已经执行了保留)。

但是,如果它返回YES,那么你需要为docController实现委托方法,并在菜单被解除时释放它(在这种情况下,它将是: - (void)documentInteractionControllerDidDismissOptionsMenu:(UIDocumentInteractionController *)controller
被叫。

修改 我想在这里进行修正:

如果取消弹出菜单,上一个答案将会崩溃。基本上没有任何好方法来创建一次性DocController。相反,我认为最好只为viewcontroller中的每个文件创建一个,并在完成后解除分配。否则,您将遇到无数可能的情况,DocController将过早发布并崩溃。

答案 2 :(得分:2)

当呈现的视图控制器依赖于它时,UIDocumentInteractionController被释放,导致此错误(正如其他人所提到的那样)。这是一个简单的错误,并在引用计数环境中创建对该视图控制器的强引用将解决该问题。通过响应委托方法,可以在不再需要时释放该对象。

这令人困惑的原因是Cocoa中的其他一些工具外观相似,不需要保持相同的方式。例如,UIImagePickerControllerUIActivityViewController可以在方法中创建并显示,而不会出现问题。

这些其他示例与UIDocumentInteractionController之间的区别在于其他组件都是UIViewController的子类。当它们被推到导航堆栈或呈现时,它们由导航堆栈或呈现视图控制器保留。当他们被解雇时,该参考被删除,他们被释放。 UIDocumentInteractionController不是UIViewController。相反,它提供了可以显示相关界面的视图控制器,但重要的是不要(因为它会导致保留周期)保留文档交互控制器。因此,无论是谁创建文档控制器,只要所呈现的界面需要它,就必须保持对它的强引用。

此示例与接受的答案基本相同,但使用ARC友好样式保留对象。

@interface MYViewController : UIViewController <UIDocumentInteractionControllerDelegate>

@property (nonatomic, strong) UIDocumentInteractionController *documentInteractionController;

@end

@implementation MYViewController

- (void)presentDocumentWithURL:(NSURL*)url {
    self.documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:url];
    self.documentInteractionController.delegate = self;
    [self.documentInteractionController presentPreviewAnimated:YES];
}

- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller {
    self.documentInteractionController = nil;
}

@end

答案 3 :(得分:1)

SWIFT 3

控制器变量:

var documentIteratorController : UIDocumentInteractionController?

通话方式:

documentIteratorController = UIDocumentInteractionController(url: reportURL)
documentIteratorController?.delegate = self
documentIteratorController?.presentOptionsMenu(from: self.printButton.frame, in: self.view, animated: true)

答案 4 :(得分:0)

用克里斯蒂安的技术......

如果您决定从视图中的不同按钮而不是导航栏中启动不同的PDF,请不要使用:

[controller autorelease];

因为它会删除控制器,所以在第一次使用后进一步的实例将无效。

但如果您正在使用它,您可能想说

[self.controller autorelease];

答案 5 :(得分:0)

我通过创建属性然后使用此代码解决了这个问题。

    [_DocController dismissMenuAnimated:NO];
    _DocController = [UIDocumentInteractionController interactionControllerWithURL:url];
    //docController.delegate = self;

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
    {
        [_DocController presentOptionsMenuFromRect:((UIView*)control).bounds inView:control animated:YES];
    }
    else
    {
        [_DocController presentOptionsMenuFromBarButtonItem:control animated:YES];
    }

dismissMenuAnimated对于防止UIPopover Dealloc错误非常重要。最常见的错误是当popOver仍然显示时,再次按下按钮以显示弹出窗口。