2013-10-07 24 views
13

Ho un'applicazione basata NSDocument che utilizza filewrappers di salvare e caricare i propri dati. Il documento può avere tutti i tipi di risorse, quindi non voglio caricare tutto in memoria. Potrei fare qualcosa di fondamentalmente sbagliato, ma non appena cambio un file (interno) e poi salvo, non riesco a leggere nessun file che non è stato caricato in memoria.NSFileWrapper, lazy loading e il salvataggio

Ho separato il codice in questione in un progetto separato per riprodurre questo comportamento, e ottenere gli stessi risultati. Il flusso di base è questo:

  • Carico un documento esistente dal disco. Il file mainWrapper è un archivio di directory (che chiamerò principale) contenente altri due filtri di linea (sub1 e sub2). I due filtri interni sono non caricati a questo punto.
  • Quando l'utente desidera modificare sub1, viene caricato dal disco.
  • L'utente salva il documento
  • Se l'utente desidera modificare l'altro file (sub2), non può caricare. L'errore che appare:

    -[NSFileWrapper regularFileContents] tried to read the file wrapper's contents lazily but an error occurred: The file couldn’t be opened because it doesn’t exist. 
    

Ecco il codice rilevante nel mio progetto:

Questo codice potrebbe essere più facile da leggere in questo gist: https://gist.github.com/bob-codingdutchmen/6869871

#define FileName01 @"testfile1.txt" 
#define FileName02 @"testfile2.txt" 

/** 
* Only called when initializing a NEW document 
*/ 
-(id)initWithType:(NSString *)typeName error:(NSError *__autoreleasing *)outError { 
    self = [self init]; 
    if (self) { 
     self.myWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil]; 

     NSLog(@"Initializing new document..."); 

     NSString *testString1 = @"Lorem ipsum first sub file"; 
     NSString *testString2 = @"This is the second sub file with completely unrelated contents"; 

     NSFileWrapper *w1 = [[NSFileWrapper alloc] initRegularFileWithContents:[testString1 dataUsingEncoding:NSUTF8StringEncoding]]; 
     NSFileWrapper *w2 = [[NSFileWrapper alloc] initRegularFileWithContents:[testString2 dataUsingEncoding:NSUTF8StringEncoding]]; 

     w1.preferredFilename = FileName01; 
     w2.preferredFilename = FileName02; 

     [self.myWrapper addFileWrapper:w1]; 
     [self.myWrapper addFileWrapper:w2]; 

    } 
    return self; 
} 

-(NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError *__autoreleasing *)outError { 

    // This obviously wouldn't happen here normally, but it illustrates 
    // how the contents of the first file would be replaced 
    NSFileWrapper *w1 = [self.myWrapper.fileWrappers objectForKey:FileName01]; 
    [self.myWrapper removeFileWrapper:w1]; 

    NSFileWrapper *new1 = [[NSFileWrapper alloc] initRegularFileWithContents:[@"New file contents" dataUsingEncoding:NSUTF8StringEncoding]]; 
    new1.preferredFilename = FileName01; 

    [self.myWrapper addFileWrapper:new1]; 

    return self.myWrapper; 
} 

-(BOOL)readFromFileWrapper:(NSFileWrapper *)fileWrapper ofType:(NSString *)typeName error:(NSError *__autoreleasing *)outError { 
    self.myWrapper = fileWrapper; 
    return YES; 
} 

- (IBAction)button1Pressed:(id)sender { 
    // Read from file1 and show result in field1 
    NSFileWrapper *w1 = [[self.myWrapper fileWrappers] objectForKey:FileName01]; 
    NSString *string1 = [[NSString alloc] initWithData:w1.regularFileContents encoding:NSUTF8StringEncoding]; 
    [self.field1 setStringValue:string1]; 
} 

- (IBAction)button2Pressed:(id)sender { 
    // Read from file2 and show result in field2 
    NSFileWrapper *w2 = [[self.myWrapper fileWrappers] objectForKey:FileName02]; 
    NSString *string2 = [[NSString alloc] initWithData:w2.regularFileContents encoding:NSUTF8StringEncoding]; 
    [self.field2 setStringValue:string2]; 
} 

I due metodi in basso sono solo per l'aggiornamento dell'interfaccia utente, così posso vedere cosa succede.

  • Per modificare il contenuto di un file, rimuovo il fileWrapper esistente e ne aggiungo uno nuovo. Questo è l'unico modo in cui ho trovato di modificare il contenuto di un file e il modo in cui l'ho visto in altre risposte SO.

  • Quando un documento viene caricato da disco, tengo le fileWrapper intorno in modo da poter usare (chiamati myWrapper nel codice sopra)

I documenti di Apple dicono che NSFileWrapper supporta il caricamento pigro e risparmio incrementale, quindi presumo che il mio codice abbia qualche difetto fondamentale che non riesco a vedere.

+0

Il documento supporta il controllo delle versioni? –

+0

Non ne sono sicuro, quindi penso di no :) Non ho fatto nulla per supportarlo. Cambierebbe qualcosa? Approfondirò in seguito, –

+1

Poiché sto utilizzando un'impostazione NSDocument, stavo supportando il controllo delle versioni. Ho provato a disattivarlo, ma il risultato è lo stesso –

risposta

1

Un NSFileWrapper è essenzialmente un wrapper per un nodo di file UNIX. Se il file viene spostato, il wrapper rimane valido.

Il problema yo sembrano avere è che la creazione di un nuovo involucro file durante il risparmio è una nuova cartella. E il sistema elimina il precedente wrapper, incluso sub2.

per ottenere ciò che si vuole è necessario modificare al risparmio incrementale, vale a dire solo il risparmio parti modificate in atto. Vedere "save in place" in NSDocument.

1

nel metodo -fileWrapperOfType:error:, provare a costruire un nuovo involucro file che ha nuovi contenuti per i membri modificati e fa riferimento ai vecchi involucri di file per i membri invariati.

0

In seguito la documentazione per addFileWrapper: si aggiunge un bambino (sottodirectory) ad esso, significa

directory/

  1. addfileWrapper: nomefile1 directory/nomefile1/

  2. addfileWrapper: nomefile2 directory/fileName1/fileName2. Questo file non esiste.

devi usare addRegularFileWithContents: preferredFilename: invece.

Problemi correlati