Странная проблема с UIDocumentInteractionController

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

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], пока все еще видны. '

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

Ответы

Ответ 1

Чтобы просмотреть документ с помощью "выпадающего" UIDocumentInteractionController, вы должны сохранить его после взаимодействияControllerWithURL и автообновить его в документе 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];
}

Ответ 2

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

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

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

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

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

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

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

Ответ 3

Эта ошибка вызвана (как указывалось другими) выпуском 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

Ответ 4

SWIFT 3

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

var documentIteratorController : UIDocumentInteractionController?

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

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

Ответ 5

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

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

[автореферат контроллера];

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

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

[self.controller autorelease];

Ответ 6

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

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

Устранение отклонения является важным для предотвращения ошибки Uallopover Dealloc. Наиболее распространенным явлением ошибки было то, что popOver все еще показывался, и вы снова нажали кнопку, чтобы отобразить popover.