Странная проблема с 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.