2012-10-16 13 views
9

Ich verwende NSFileWrapper für mein Paketdokument. Manchmal, wenn ich die Daten einer Datei im Paket anfrage, bekomme ich nil. DieseNSFileWrapper gibt Null zurück, manchmal

ist, wie ich die Daten einer Datei innerhalb des Pakets abfragen:

- (NSData*) dataOfFile(NSString*)filename { 
    NSFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename]; 
    return fileWrapper.regularFileContents; // This returns nil sometimes. Why? 
} 

Diese Methode beginnt schließlich Null für einige Dateien Rückkehr (nicht alle). Leider ist es mir nicht gelungen, das Problem konsequent zu reproduzieren.

Falls es hilft, das ist, wie ich das Paket öffnen:

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

Dies ist, wie ich die Daten einer Datei innerhalb des Pakets aktualisieren:

- (void) updateFile:(NSString*)filename withData:(NSData*)data { 
    SBFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename]; 
    if (fileWrapper) { 
     [self.documentFileWrapper removeFileWrapper:fileWrapper]; 
    } 
    NSFileWrapper *fileWrapper = [[SBFileWrapper alloc] initRegularFileWithContents:data ]; 
    fileWrapper.preferredFilename = filename; 
    [self.documentFileWrapper addFileWrapper:fileWrapper]; 
} 

Dies ist, wie ich sparen das Paket:

- (NSFileWrapper*) fileWrapperOfType:(NSString *)typeName error:(NSError *__autoreleasing *)outError { 
    return self.documentFileWrapper; 
} 

Warum kann das passieren? Gibt es einen Weg, das zu verhindern?

Die Dokumentation von regularFileContents erscheint über dieses Problem zu sprechen:

This method may return nil if the user modifies the file after you call readFromURL:options:error: or initWithURL:options:error: but before NSFileWrapper has read the contents of the file. Use the NSFileWrapperReadingImmediate reading option to reduce the likelihood of that problem.

Aber ich verstehe nicht, was muss geändert werden in dem obigen Code zu verhindern, diese Situation.

Gescheiterte Versuche

Ich habe versucht, das Dokument, wenn regularFileContents Rückkehr null Speicher, aber es gibt immer noch danach gleich Null. Gefällt mir:

- (NSData*) dataOfFile(NSString*)filename { 
    NSFileWrapper *fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename]; 
    NSData *data = fileWrapper.regularFileContents; 
    if (!data) { 
      [self saveDocument:nil]; 
      fileWrapper = [self.documentFileWrapper.fileWrappers objectForKey:filename]; 
      data = fileWrapper.regularFileContents; 
    } 
    return data; 
} 
+0

Dies ist eine verrückte Vermutung, aber ich frage mich, ob Spotlight die Dateiattribute ändert, nachdem Sie gespeichert haben (wie es die Datei oder etwas neu indiziert)? Ich bin ein wenig neugierig, warum Sie sparen, nachdem es versagt hat; warum nicht wieder öffnen? Raten Sie nur, um Ihnen ein paar Ideen zu geben. – Dad

+0

Wild rate, aber ich denke, dein Objekt wird freigegeben. Vielleicht läuft etwas falsch mit dem Alloc. Hast du eine Analyse versucht? Sei vorsichtig mit alloc & init (und self. + Autorelease und release). – Roger

Antwort

3

Es gibt nicht genug Code, um zu sehen, was wirklich los ist. Die Ursache liegt jedoch darin, dass NSFileWrapper genau das ist, was der Name impliziert: Ein Objekt, das eine Datei oder ein Verzeichnis darstellt. Daher kann die tatsächliche Datei oder das Verzeichnis leicht mit dem Objekt, das sich im Speicher befindet, "nicht mehr synchron" sein. Immer wenn NSFileWrapper feststellt, dass dies aufgetreten ist, gibt es für bestimmte Operationen nil zurück. Die Lösung besteht darin, NSFileWrapper Objekte kurzlebig zu machen. Erstellen und öffnen Sie sie genau dann, wenn Sie sie benötigen, und speichern und schließen Sie dann so schnell wie möglich.

Insbesondere sieht es so aus, als ob Ihr Code einen Zeiger auf einen Paketverzeichnis-Wrapper für eine lange Zeit hält und davon ausgeht, dass er immer gültig ist. Wenn sich das Verzeichnis aus irgendeinem Grund ändert, ist dies nicht der Fall. Recode, so dass Sie jedes Mal, wenn Sie es brauchen, einen neuen Paketverzeichnis-Wrapper erhalten, und das Problem sollte verschwinden.

0

Wenn sich die Datei auf der Festplatte ändert, erhalten Sie null (wie @Gene sagt). Allerdings können Sie dies überprüfen, indem matchesContentsOfURL: Methode gemessen, die:

determines whether a disk representation may have changed, based on the file attributes stored the last time the file was read or written. If the file wrapper’s modification time or access permissions are different from those of the file on disk, this method returns YES. You can then use readFromURL:options:error:

Dieses von Working with File Wrappers Apple-Dokumentation.

Hinweis: dieser aus dem Intro zu diesem Abschnitt:

Because the purpose of a file wrapper is to represent files in memory, it’s very loosely coupled to any disk representation. A file wrapper doesn’t record the path to the disk representation of its contents. This allows you to save the same file wrapper with different URLs, but it also requires you to record those URLs if you want to update the file wrapper from disk later.

So werden Sie die URL der Originaldatei speichern müssen, wenn Sie wollen/müssen es noch einmal zu lesen.

Interessant zu hören, was matchesContentsofURL: zurückkehrt, wenn Sie keine Ergebnisse sehen.