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

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

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

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

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

  • -в этом
  • -initWithContentsOfURL: OfType: ошибка:
  • -initForURL:withContentsOfURL: OfType: ошибка:
  • -initWithType: ошибка:

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

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

2 ответа

Решение

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"S.

Кодирование состояния окна включается двумя способами: 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 для вас.

Другие вопросы по тегам