13 Stimmen

NSFileWrapper, Lazy Loading und Speichern

Ich habe eine NSDocument-basierte Anwendung, die FileWrappers verwendet, um ihre Daten zu speichern und zu laden. Das Dokument kann alle möglichen Ressourcen haben, daher möchte ich nicht alles in den Speicher laden. Möglicherweise mache ich etwas grundlegend falsch, aber sobald ich eine (innere) Datei ändere und dann speichere, kann ich keine Datei lesen, die nicht in den Speicher geladen wurde.

Ich habe den relevanten Code in ein separates Projekt aufgeteilt, um dieses Verhalten zu reproduzieren, und ich erhalte die gleichen Ergebnisse. Der grundlegende Ablauf ist wie folgt:

  • Ich lade ein vorhandenes Dokument von der Festplatte. Der Haupt-FileWrapper ist ein Verzeichnis-FileWrapper (den ich main nennen werde), der zwei andere FileWrappers ( sub1 und sub2) enthält. Die beiden inneren FileWrapper sind zu diesem Zeitpunkt nicht geladen.
  • Wenn der Benutzer sub1 bearbeiten möchte, wird es von der Festplatte geladen.
  • Der Benutzer speichert das Dokument
  • Wenn der Benutzer die andere Datei bearbeiten möchte (sub2), kann sie nicht geladen werden. Der Fehler, der erscheint:

    -[NSFileWrapper regularFileContents] hat versucht, die Datei-Inhalte des FileWrappers träge zu lesen, aber ein Fehler ist aufgetreten: Die Datei konnte nicht geöffnet werden, weil sie nicht existiert.

Hier ist der relevante Code in meinem Projekt:

Dieser Code könnte einfacher in diesem Gist zu lesen sein: https://gist.github.com/bob-codingdutchmen/6869871

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

/**
 *  Nur aufgerufen bei der Initialisierung eines NEUEN Dokuments
 */
-(id)initWithType:(NSString *)typeName error:(NSError *__autoreleasing *)outError {
    self = [self init];
    if (self) {
        self.myWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];

        NSLog(@"Initialisiere neues Dokument...");

        NSString *testString1 = @"Lorem Ipsum erste Unterdatei";
        NSString *testString2 = @"Dies ist die zweite Unterdatei mit völlig unabhängigen Inhalten";

        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 {

    // Dies würde normalerweise hier nicht passieren, aber es veranschaulicht
    // wie die Inhalte der ersten Datei ersetzt würden
    NSFileWrapper *w1 = [self.myWrapper.fileWrappers objectForKey:FileName01];
    [self.myWrapper removeFileWrapper:w1];

    NSFileWrapper *new1 = [[NSFileWrapper alloc] initRegularFileWithContents:[@"Neue Datei Inhalte" 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 {
    // Aus Datei1 lesen und Ergebnis in Feld1 anzeigen
    NSFileWrapper *w1 = [[self.myWrapper fileWrappers] objectForKey:FileName01];
    NSString *string1 = [[NSString alloc] initWithData:w1.regularFileContents encoding:NSUTF8StringEncoding];
    [self.field1 setStringValue:string1];
}

- (IBAction)button2Pressed:(id)sender {
    // Aus Datei2 lesen und Ergebnis in Feld2 anzeigen
    NSFileWrapper *w2 = [[self.myWrapper fileWrappers] objectForKey:FileName02];
    NSString *string2 = [[NSString alloc] initWithData:w2.regularFileContents encoding:NSUTF8StringEncoding];
    [self.field2 setStringValue:string2];
}

Die unteren beiden Methoden dienen nur zur Aktualisierung der Benutzeroberfläche, damit ich sehen kann, was passiert.

  • Um den Inhalt einer Datei zu ändern, entferne ich den vorhandenen FileWrapper und füge einen neuen hinzu. Dies ist die einzige Methode, die ich gefunden habe, um den Inhalt einer Datei zu ändern, und die Art und Weise, wie ich es in anderen SO-Antworten gesehen habe.

  • Wenn ein Dokument von der Festplatte geladen wird, halte ich den FileWrapper bereit, um ihn nutzen zu können (im obigen Code myWrapper genannt)

Laut den Apple-Dokumenten unterstützt NSFileWrapper das träge Laden und inkrementelle Speichern, daher gehe ich davon aus, dass mein Code einen grundlegenden Fehler hat, den ich nicht erkennen kann.

1voto

Cocoanetics Punkte 8061

Ein NSFileWrapper ist im Wesentlichen ein Wrapper um einen Unix-Dateiknoten. Wenn die Datei verschoben wird, bleibt der Wrapper gültig.

Das Problem, das Sie zu haben scheinen, ist, dass beim Speichern ein neuer Dateiwrapper erstellt wird, der sich in einem neuen Ordner befindet. Und das System löscht Ihren vorherigen Wrapper einschließlich sub2.

Um zu erreichen, was Sie möchten, müssen Sie zu inkrementellem Speichern wechseln, d.h. Nur geänderte Teile an Ort und Stelle speichern. Siehe "speichern am Ort" in NSDocument.

1voto

tjw Punkte 972

In Ihrer Methode -fileWrapperOfType:error: versuchen Sie, einen neuen Datei-Wrapper zu erstellen, der neue Inhalte für die geänderten Elemente enthält und auf die alten Datei-Wrapper für die unveränderten Elemente verweist.

0voto

macrene Punkte 198

Die Dokumentation zur Hinzufügung von addFileWrapper besagt: Sie fügen ein Kind (Unterverzeichnis) hinzu, bedeutet

Verzeichnis/

  1. addfileWrapper:fileName1 Verzeichnis/fileName1/

  2. addfileWrapper:fileName2 Verzeichnis/fileName1/fileName2. Diese Datei existiert nicht.

Sie müssen stattdessen addRegularFileWithContents:preferredFilename: verwenden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X