2012-12-12 12 views
13

Mam aplikację opartą na NSDocument z podklasą NSDocumentController. Mój dokument NSD współpracuje zarówno z adresami URL, jak i adresami URL z niestandardowym schematem korzystającym z usługi internetowej.Aplikacja oparta na dokumentach nie odtwarza dokumentów z adresami URL nie będącymi plikami

Obsługuję większość operacji ładowania i zapisywania przy użyciu niestandardowego kodu, w tym -saveToURL:ofType:forSaveOperation:completionHandler:. +autosavesInPlace zwraca YES.

Problem, który mam: dokumenty z niestandardowym schematem URL nie są przywracane podczas uruchamiania. Dokumenty ze schematem URL pliku to - zarówno zwykłe dokumenty zapisane w plikach, jak i dokumenty bez tytułu, które są automatycznie zapisywane.

Po pozostawieniu otwartych dokumentów serwerowych i zamknięciu aplikacji, żadne metody NSDocument nie są wywoływane przy ponownym uruchomieniu. W szczególności, żaden z czterech inicjalizatorów nazywa się:

  • -init
  • -initWithContentsOfURL: ofType: error:
  • -initForURL: withContentsOfURL: ofType: error:
  • -initWithType: error:

Metoda NSDocumentController -reopenDocumentForURL:withContentsOfURL:display:completionHandler: również nie jest nazywana.

W jaki sposób i kiedy dokument jest kodowany jako "przywracany"? Jak i kiedy są dekodowane?

Odpowiedz

13

NSDocument jest odpowiedzialny za kodowanie stanu przywracania w -encodeRestorableStateWithCoder:, a NSDocumentController jest odpowiedzialny za dekodowanie stanu przywracania dokumentów i ponowne otwieranie dokumentów w +restoreWindowWithIdentifier:state:completionHandler:. Zobacz pomocne komentarze w NSDocumentRestoration.h.

Gdy NSDocument koduje adres URL, wydaje się korzystać z metod zakładki NSURL. Problem polega na tym, że metody te działają tylko z adresami systemu plików. (Możliwe, że nie-plikowe adresy URL będą kodować, ale nie będą poprawnie dekodowane.)

Aby rozwiązać problem, należy zastąpić kodowanie wystąpień NSDocument, które korzystają ze schematu niestandardowego, i podobnie, dekodowanie tych dokumentów.

NSDocument podklasy:

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

NSDocumentController podklasy:

+ (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]; 
} 

Zachowanie lub opiekun realizacja wynika z metody komentarzu Apple w NSDocumentRestoration.h i powinny być mniej więcej takie same jak super.

4

Kodowanie stanu okna jest włączane dwiema metodami na NSWindow. Wywołanie setRestorable: w oknie oznacza to, że można go zapisać i przywrócić po ponownym uruchomieniu, a następnie wywołanie setRestorationClass: pozwala określić klasę, która będzie obsługiwać odtwarzanie tego zapisanego okna.

Domyślnie AppKit ustawia NSDocumentController jako klasę odtwarzania okien kontrolowanych przez obiekty NSDocument. Rzeczywiste przywrócenie odbywa się przez wywołanie metody +restoreWindowWithIdentifier:state:completionHandler:, zdefiniowanej przez protokół . W przypadku dokumentów implementuje tę metodę i odtwarza obiekt NSDocument na podstawie stanu zakodowanego w instancji NSCoder przekazanej do metody.

Tak więc, teoretycznie, gdybyś miał podklasę NSDocumentController i nadpisałeś tę metodę, dałoby ci to możliwość przywrócenia dokumentów zapisanych przez mechanizm przywracania stanu. Jednak, o ile wiem, klucze używane przez NSDocumentController do przechowywania stanu nie są nigdzie udokumentowane, więc nie sądzę, że byłby niezawodny sposób na przywrócenie bezpośrednio ze stanu, który przechowuje sam NSDocumentController.

Do tego wsparcia, to prawdopodobnie trzeba kodować cały stan dokumentu siebie, poprzez wdrożenie -encodeRestorableStateWithCoder: na NSWindow są kodowane i/lub wdrożenia metody window:willEncodeRestorableState: Delegat okna. Obie te metody przekazują ci instancję NSCoder, której możesz użyć do zakodowania swojego stanu. Tutaj możesz zakodować swój niestandardowy adres URL wraz z wszelkimi innymi powiązanymi danymi potrzebnymi do zapisania/przywrócenia stanu. Następnie można dekodować ten stan w metodzie restoreWindowWithIdentifier:state:completionHandler:.

Ponieważ będziesz mieć kilka dokumentów ze zwykłymi adresami URL plików, a niektóre z niestandardowymi adresami URL, podchodzę do tego, tworząc oddzielną klasę odpowiedzialną za dekodowanie stanu dokumentu i ustawiając go jako klasę przywracania tylko dla twoich dokumentów niestandardowe adresy URL, pozostawiając NSDocumentController do obsługi dokumentów z adresami URL plików.

+2

To była bardzo pomocna pomoc w rozpoczęciu pracy. Okazuje się, że historia jest bardziej skomplikowana: to w rzeczywistości NSDocument, a nie NSWindow, który jest odpowiedzialny za kodowanie stanu * document * (numerowane ID, URL, ma ostatnie zmiany, typ) we własnej implementacji '-encodeRestorableStateWithCoder:'. NSDocumentController używa tych informacji o stanie do przywrócenia dokumentu, a następnie wywołuje '-makeWindowControllers' i NSApplication (lub program obsługi zakończenia NSApplication?) Przywraca okno. Ponadto, gdy używana jest niestandardowa podklasa NSDocumentController, AppKit ustawia * tę * klasę jako 'restorationClass'. – paulmelnikow

Powiązane problemy