我不知道这段代码有什么问题,但每当我运行应用程序时,在显示菜单后,应用程序崩溃。
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 仍然可见。'
我现在该怎么办?
答案 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中的其他一些工具外观相似,不需要保持相同的方式。例如,UIImagePickerController
或UIActivityViewController
可以在方法中创建并显示,而不会出现问题。
这些其他示例与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仍然显示时,再次按下按钮以显示弹出窗口。