2012-12-12 4 views
13

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

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

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

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

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

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

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

ответ

13

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.

4

Кодирование состояния окна разрешено двумя способами на 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-адресами файлов для вас.

+2

Это была большая помощь при запуске. Оказывается, история сложнее: на самом деле это NSDocument, а не NSWindow, который отвечает за кодирование состояния * document * (нумерованный идентификатор, url, имеет последние изменения, тип) в собственной реализации '-encodeRestorableStateWithCoder:'. NSDocumentController использует эту информацию о состоянии для восстановления документа, затем вызывает '-makeWindowControllers' и NSApplication (или обработчик завершения NSApplication?), Восстанавливает окно. Кроме того, при использовании пользовательского подкласса NSDocumentController AppKit устанавливает * этот * класс как 'restoreClass'. – paulmelnikow

Смежные вопросы