2012-12-12 15 views
13

Ho un'applicazione basata su NSDocument con una sottoclasse NSDocumentController. Il mio NSDocument funziona con entrambi gli URL di file e URL con uno schema personalizzato che utilizza un servizio web.L'applicazione basata su documenti non ripristina i documenti con URL non file

Gestisco gran parte del caricamento e del salvataggio utilizzando un codice personalizzato, incluso -saveToURL:ofType:forSaveOperation:completionHandler:. +autosavesInPlace restituisce YES.

Il problema riscontrato: i documenti con lo schema URL personalizzato non vengono ripristinati all'avvio. I documenti con lo schema URL file sono - sia i documenti normali salvati in file, sia i documenti senza titolo che sono salvati automaticamente.

Dopo aver lasciato aperti i documenti basati su server e chiuso l'app, nessun metodo NSDocument sembra essere richiamato al riavvio. In particolare, nessuno dei quattro inizializzatori si chiama:

  • -init
  • -initWithContentsOfURL: OfType: errore:
  • -initForURL: withContentsOfURL: OfType: errore:
  • -initWithType: errore:

Il metodo NSDocumentController -reopenDocumentForURL:withContentsOfURL:display:completionHandler: non viene chiamato neanche.

Come e quando viene codificato lo stato ripristinabile dei documenti? Come e quando vengono decodificati?

risposta

13

NSDocument è responsabile della codifica dello stato ripristinabile in -encodeRestorableStateWithCoder: e NSDocumentController è responsabile della decodifica dello stato ripristinabile dei documenti e della riapertura dei documenti in +restoreWindowWithIdentifier:state:completionHandler:. Fare riferimento ai commenti utili in NSDocumentRestoration.h.

Quando NSDocument codifica l'URL, sembra che utilizzi i metodi segnalibro di NSURL. Il problema è che questi metodi funzionano solo con gli URL del file system. (È possibile che gli URL non file vengano codificati, ma non verranno decodificati correttamente.)

Per risolvere il problema, eseguire l'override della codifica delle istanze di NSDocument che utilizzano lo schema personalizzato e, analogamente, la decodifica di tali documenti.

NSDocument sottoclasse:

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

NSDocumentController sottoclasse:

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

Il comportamento o il gestore di completamento Dalle metodo commento di Apple in NSDocumentRestoration.h e dovrebbe essere più o meno lo stesso di super 's.

4

La codifica dello stato della finestra è abilitata con due metodi su NSWindow. Chiamando setRestorable: nella finestra, viene contrassegnato come uno che può essere salvato e ripristinato al riavvio, quindi chiamare setRestorationClass: consente di specificare una classe che gestirà la ricreazione della finestra salvata.

Per impostazione predefinita, AppKit imposta NSDocumentController come classe di ripristino di finestre controllate dagli oggetti NSDocument. Il ripristino effettivo viene effettuato chiamando il metodo +restoreWindowWithIdentifier:state:completionHandler:, definito dal protocollo NSWindowRestoration. Per i documenti, NSDocumentController implementa tale metodo e ricrea l'oggetto NSDocument in base allo stato codificato nell'istanza NSCoder passata nel metodo.

Quindi, in teoria, se si dovesse creare una sottoclasse di NSDocumentController e sovrascrivere tale metodo, si otterrebbe l'opportunità di ripristinare i documenti salvati dal meccanismo di ripristino dello stato. Tuttavia, per quanto ne so, le chiavi utilizzate da NSDocumentController per memorizzare lo stato non sono documentate da nessuna parte, quindi non credo che ci sarebbe un modo affidabile per ripristinare direttamente dallo stato che NSDocumentController memorizza se stesso.

A sostegno di questo, si sarebbe probabilmente necessario per codificare l'intero stato per il documento da soli, mediante l'attuazione di -encodeRestorableStateWithCoder: sul NSWindow in fase di codifica, e/o implementare il metodo window:willEncodeRestorableState: delegato per la finestra. Entrambi questi metodi ti passano un'istanza NSCoder che puoi utilizzare per codificare il tuo stato. È qui che dovresti codificare il tuo URL personalizzato, insieme a qualsiasi altro dato associato di cui hai bisogno per salvare/ripristinare il tuo stato. Dovresti quindi decodificare quello stato nel metodo restoreWindowWithIdentifier:state:completionHandler:.

Dato che avrete alcuni documenti con normali URL di file e alcuni con i vostri URL personalizzati, mi avvicinerei a ciò creando una classe separata responsabile della decodifica dello stato del documento e impostandola come classe di ripristino solo per i vostri documenti con URL personalizzati, lasciando NSDocumentController per gestire i documenti con gli URL dei file per te.

+2

Questo è stato un grande aiuto per iniziare. Si scopre che la storia è più complicata: in realtà è NSDocument, non NSWindow, che è responsabile della codifica dello stato * document * (ID numerato, url, ha cambiamenti recenti, tipo) nella sua implementazione di '-encodeRestorableStateWithCoder:'. NSDocumentController utilizza le informazioni di stato per ripristinare il documento, quindi richiama '-makeWindowControllers' e NSApplication (o il gestore di completamento di NSApplication?) Ripristina la finestra. Inoltre, quando si utilizza una sottoclasse personalizzata di NSDocumentController, AppKit imposta * that * class come 'restorationClass'. – paulmelnikow

Problemi correlati