Подтвердить что ты не робот

Приложение на основе документов не восстанавливает документы с не файловыми URL-адресами

У меня есть приложение на основе NSDocument с подклассом NSDocumentController. Мой NSDocument работает как с URL-адресами файлов, так и с URL-адресами с пользовательской схемой, использующей веб-службу.

Я обрабатываю большую часть загрузки и сохранения с использованием настраиваемого кода, включая -saveToURL:ofType:forSaveOperation:completionHandler:. +autosavesInPlace возвращает YES.

Проблема, с которой я столкнулся: документы с настраиваемой схемой URL не восстанавливаются при запуске. Документы с файловой схемой URL-адреса - это как обычные документы, сохраненные в файлах, так и неопубликованные документы, которые автосохранены.

После выхода из открытых серверных документов и выхода из приложения, методы NSDocument, как представляется, вызывают при перезагрузке. В частности, ни один из четырех инициализаторов не называется:

  • -init
  • -initWithContentsOfURL: OfType: ошибка:
  • -initForURL: withContentsOfURL: OfType: ошибка:
  • -initWithType: ошибка:

Метод NSDocumentController -reopenDocumentForURL:withContentsOfURL:display:completionHandler: также не вызывается.

Как и когда закодировано состояние восстановления документов? Как и когда они декодируются?

4b9b3361

Ответ 1

NSDocument отвечает за кодирование своего восстанавливаемого состояния в -encodeRestorableStateWithCoder:, а NSDocumentController отвечает за восстановление восстановительного состояния документов и повторное открытие документов в +restoreWindowWithIdentifier:state:completionHandler:. Обратитесь к полезным комментариям в NSDocumentRestoration.h.

Когда NSDocument кодирует URL-адрес, он, как представляется, использует методы закладки NSURL. Проблема в том, что эти методы работают только с URL-адресами файловой системы. (Возможно, будут кодироваться не файловые URL-адреса, но они не будут должным образом декодироваться.)

Чтобы устранить проблему, переопределите кодировку экземпляров NSDocument, которые используют пользовательскую схему, а также расшифровку этих документов.

Подкласс NSDocument:

- (void) encodeRestorableStateWithCoder:(NSCoder *) coder {
    if ([self.fileURL.scheme isEqualToString:@"customscheme"])
        [coder encodeObject:self.fileURL forKey:@"MyDocumentAutoreopenURL"];
    else
        [super encodeRestorableStateWithCoder:coder];
}

Подкласс NSDocumentController:

+ (void) restoreWindowWithIdentifier:(NSString *) identifier
                               state:(NSCoder *) state
                   completionHandler:(void (^)(NSWindow *, NSError *)) completionHandler {

    NSURL *autoreopenURL = [state decodeObjectForKey:@"MyDocumentAutoreopenURL"];
    if (autoreopenURL) {
        [[self sharedDocumentController]
         reopenDocumentForURL:autoreopenURL
         withContentsOfURL:autoreopenURL
         display:NO
         completionHandler:^(NSDocument *document, BOOL documentWasAlreadyOpen, NSError *error) {

             NSWindow *resultWindow = nil;
             if (!documentWasAlreadyOpen) {

                 if (![[document windowControllers] count])
                     [document makeWindowControllers];

                 if (1 == document.windowControllers.count)
                     resultWindow = [[document.windowControllers objectAtIndex:0] window];
                 else {
                     for (NSWindowController *wc in document.windowControllers)
                         if ([wc.window.identifier isEqual:identifier]) {
                             resultWindow = wc.window;
                             break;
                         }
                 }
             }
             completionHandler(resultWindow, error);
         }
         ];
    } else
        [super restoreWindowWithIdentifier:identifier
                                     state:state
                         completionHandler:completionHandler];
}

Поведение или обработчик завершения следует из комментария метода Apple в NSDocumentRestoration.h и должно быть примерно таким же, как super.

Ответ 2

Кодирование состояния окна включено двумя способами на NSWindow. Вызов setRestorable: в окне помечает его как тот, который можно сохранить и восстановить при повторном запуске, а затем вызов setRestorationClass: позволяет указать класс, который будет обрабатывать воссоздание этого сохраненного окна.

По умолчанию AppKit устанавливает NSDocumentController как класс восстановления окон, управляемых объектами NSDocument. Фактическое восстановление выполняется путем вызова метода +restoreWindowWithIdentifier:state:completionHandler:, определенного протоколом NSWindowRestoration. Для документов NSDocumentController реализует этот метод и воссоздает объект NSDocument на основе состояния, закодированного в экземпляре NSCoder, переданного в метод.

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

Чтобы поддержать это, вам, вероятно, понадобится кодировать все состояние для самого документа, реализовав -encodeRestorableStateWithCoder: в NSWindow, который будет закодирован, и/или реализует метод делегата window:willEncodeRestorableState: для окна. Оба этих метода передают вам экземпляр NSCoder, который вы можете использовать для кодирования своего состояния. То, где вы будете кодировать свой URL-адрес с настраиваемым запросом, вместе с любыми другими связанными данными, вам необходимо сохранить/восстановить свое состояние. Затем вы должны декодировать это состояние в методе restoreWindowWithIdentifier:state:completionHandler:.

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