Странная проблема с UIDocumentInteractionController - PullRequest
15 голосов
/ 26 мая 2010

Я не знаю, что не так с этим кодом, но каждый раз, когда я запускаю приложение, после отображения меню происходит сбой приложения.

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] достигнут в то время как поповер все еще видимый. '

Что мне теперь делать?

Ответы [ 6 ]

23 голосов
/ 13 августа 2010

Для предварительного просмотра документа с помощью одноразового UIDocumentInteractionController вы должны сохранить его после взаимодействия с ControlControllerWithURL и автоматически освободить его в методе UIDocumentInteractionControllerDelegate documentInteractionControllerDidDismissOptionsMenu Как отметил Дэвид Лю, его выпуск приведет к краху. Но авто-релиз работает. Я проверил, что dealloc действительно называется.

Следующий код должен работать:


- (void)previewDocumentWithURL:(NSURL*)url
{
    UIDocumentInteractionController* preview = [UIDocumentInteractionController interactionControllerWithURL:url];
    preview.delegate = self;
    [preview presentPreviewAnimated:YES];
    [preview retain];
}
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)controller
{
    [controller autorelease];
}
8 голосов
/ 28 мая 2010

Это в основном старая проблема управления памятью.

[UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]] возвращает объект с автоматическим освобождением, поэтому он будет автоматически освобожден вскоре после завершения блока кода. Я предполагаю, что это не похоже на presentModalViewController, который сохранит копию для вас, но это побочный момент.

По сути, вам нужно сохранить его до окончания блока кода. Более раздражающей частью является отслеживание того, что делает docController, чтобы вы не теряли память. Вам нужно будет проверить результат от
[docController presentOptionsMenuFromRect:rect inView:self.view animated:YES];

Если он возвращает NO, это означает, что меню никогда не появлялось, и поэтому вы должны сразу же сделать его (если вы уже сделали сохранение).

Однако, если он возвращает YES, вам нужно реализовать методы делегата для docController и освободить его, когда меню закрывается (в этом случае это будет, когда:
- (void)documentInteractionControllerDidDismissOptionsMenu:(UIDocumentInteractionController *)controller
вызывается.

EDIT: Я хочу сделать здесь поправку:

Предыдущий ответ вылетит, если всплывающее меню будет закрыто. По сути, нет действительно никакого хорошего способа создать одноразовый DocController. Вместо этого я думаю, что лучше всего создать по одному для каждого файла, который вам нужен в viewcontroller, и освободить его, когда вы закончите. В противном случае вы столкнетесь с множеством возможных случаев, когда DocController выйдет слишком рано и рухнет.

2 голосов
/ 10 сентября 2015

Эта ошибка вызвана (как уже упоминалось другими) освобождением UIDocumentInteractionController, в то время как представленный контроллер представления все еще зависит от него. Это простая ошибка, и создание сильной ссылки на этот контроллер представления в среде с подсчетом ссылок решит проблему. Объект может быть освобожден, когда он больше не нужен, отвечая на методы делегата.

Причина, по которой это сбивает с толку, заключается в том, что некоторые другие инструменты в Какао, похожие по внешнему виду, не нужно сохранять таким же образом. Например, 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
1 голос
/ 10 октября 2016

SWIFT 3

Переменная контроллера:

var documentIteratorController : UIDocumentInteractionController?

Метод вызова:

documentIteratorController = UIDocumentInteractionController(url: reportURL)
documentIteratorController?.delegate = self
documentIteratorController?.presentOptionsMenu(from: self.printButton.frame, in: self.view, animated: true)
0 голосов
/ 13 июля 2013

Я решил эту проблему, создав свойство и затем используя этот код.

    [_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. Наиболее распространенная ошибка произошла, когда всплывающее окно все еще отображалось, и вы снова нажали кнопку, чтобы отобразить всплывающее окно.

0 голосов
/ 15 сентября 2011

С техникой Кристиана ...

Если вы решили запускать разные PDF-файлы с разных кнопок в представлении, а не с панели навигации, не используйте:

[Авто-релиз контроллера];

Поскольку он удалит контроллер, дальнейшие экземпляры не будут работать после первого использования.

Но если вы используете его, вы можете сказать

[самовыпуск самоконтроллера];

...