UIDocumentInteractionController 的奇怪问题

发布于 2024-09-02 14:15:23 字数 665 浏览 2 评论 0原文

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

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 弹出窗口时达到 dealloc] 仍然可见。'

我现在该怎么办?

I don't know what wrong with this code but everytime when I run the app, after the Menu is shown, the app crash.

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];

Error I got:

*** Terminating app due to uncaught exception 'NSGenericException',
reason: '-[UIPopoverController
dealloc] reached while popover is
still visible.'

What should I do now ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

相思碎 2024-09-09 14:15: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];
}


To preview a document via a "throwaway" UIDocumentInteractionController you should retain it after interactionControllerWithURL and autorelease it in the UIDocumentInteractionControllerDelegate method documentInteractionControllerDidDismissOptionsMenu. As remarked by David Liu, releasing it will crash. But autoreleasing works. I have checked that dealloc is actually called.

The following code should work:



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

知足的幸福 2024-09-09 14:15:23

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

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

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

如果它返回NO,则意味着菜单从未显示出来,因此您应该立即对其进行释放(如果您已经是否保留)。

但是,如果它返回 YES,那么您需要实现 docController 的委托方法,并在菜单关闭时释放它(在本例中,将在以下情况下释放)
- (void)documentInteractionControllerDidDismissOptionsMenu:(UIDocumentInteractionController *)控制器
被叫。

编辑:
我想在这里进行更正:

如果弹出菜单被关闭,前面的答案将会崩溃。本质上,确实没有任何好方法来创建一次性的 DocController。相反,我认为最好为视图控制器中需要的每个文件创建一个,并在完全完成后取消分配。否则,您将遇到多种可能的情况,其中 DocController 过早发布并崩溃。

It's basically the old memory management problem.

[UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]] returns an autoreleased object, so it'll get autoreleased soon after your code block finishes. I'm guessing this is unlike presentModalViewController which will retain a copy for you, but that's a side point.

Basically, you need to retain it before your code block ends. The more annoying part is keeping track of what the docController is doing so you don't leak memory. You'll have to check the result from
[docController presentOptionsMenuFromRect:rect inView:self.view animated:YES];

If it returns NO, that means the menu never showed up, and so you should do a release on it right away (if you already did the retain).

However, if it returns YES, then you'll need to implement the delegate methods for docController, and release it when the menu is dismissed (in this case, it would be when:
- (void)documentInteractionControllerDidDismissOptionsMenu:(UIDocumentInteractionController *)controller
gets called.

EDIT:
I want to make a correction here:

The previous answer will crash if the popup menu is dismissed. Essentially there's really not any good way to create a throwaway DocController. Instead, I think it's best to just create one for every file you need in the viewcontroller, and deallocate when you're completely done. Otherwise you'll run into a myriad of possible cases where the DocController will get released too early and crash.

﹂绝世的画 2024-09-09 14:15:23

这个错误是由于 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

This error is caused (as others have mentioned) by the UIDocumentInteractionController being released while the presented view controller is still depending upon it. Thats a simple error and creating a strong reference to that view controller, in an reference counted environment, will solve the problem. The object can be released when it's no longer necessary by responding to delegate methods.

The reason this is confusing is that some other tools in Cocoa similar in appearance do not need to be retained the same way. For example UIImagePickerController or UIActivityViewController could be created and presented within a method without problem.

The difference between these other examples and UIDocumentInteractionController is that the other components are all subclasses of UIViewController. When they are pushed onto a navigation stack or presented they are retained by the navigation stack or the presenting view controller. When they are dismissed, that reference is removed andy they are released. UIDocumentInteractionController is not a UIViewController. Instead it provides view controllers which can display the relevant interface, but importantly do not (for good reason as it would cause a retain cycle) retain the document interaction controller. Because of that, whoever is creating the document controller must also maintain strong reference to it as long as it's needed by the presented interface.


This example is essentially the same as the accepted answer, but using ARC friendly style of retaining an object.

@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
栖迟 2024-09-09 14:15:23

SWIFT 3

控制器变量:

var documentIteratorController : UIDocumentInteractionController?

调用方法:

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

SWIFT 3

Controller variable:

var documentIteratorController : UIDocumentInteractionController?

Call method:

documentIteratorController = UIDocumentInteractionController(url: reportURL)
documentIteratorController?.delegate = self
documentIteratorController?.presentOptionsMenu(from: self.printButton.frame, in: self.view, animated: true)
明月夜 2024-09-09 14:15:23

使用 Christian 的技术...

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

[controller autorelease];

因为它会删除控制器,所以第一次使用后后续实例将无法工作。

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

[self.controller autorelease];

With Christian's technique...

Should you decide to launch different PDFs from different buttons in the view rather than from the navigation bar, don't use:

[controller autorelease];

Because it will remove the controller, so further instances won't work after the first use.

But if you are using it you may want to say

[self.controller autorelease];

手长情犹 2024-09-09 14:15:23

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

    [_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];
    }

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

I solved this problem by creating a property and then using this code.

    [_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];
    }

The dismissMenuAnimated is important to prevent the UIPopover Dealloc error. The most common occurance of the error was when the popOver was still showing, and you pressed the button again to display the popover.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文