2013-10-07 72 views
13

我有一個基於NSDocument的應用程序使用filewrappers來保存和加載其數據。 該文件可以有各種資源,所以我不想將所有內容加載到內存中。我可能會做一些根本性錯誤的事情,但只要我更改一個(內部)文件然後保存,我就無法讀取任何尚未加載到內存中的文件。NSFileWrapper,延遲加載和保存

我已將相關代碼分隔到單獨的項目中以重現此行爲,並且獲得了相同的結果。基本流程是這樣的:

  • 我從磁盤加載一個現有的文件。主fileWrapper是一個包含兩個其他文件包裝器(sub1sub2)的目錄文件打包程序(我將稱之爲main)。這兩個內部文件包裝是而不是在這一點上加載。
  • 當用戶想要編輯sub1時,它從磁盤加載。如果用戶希望編輯其他文件(SUB2
  • 的用戶保存文檔
  • ,它不能加載。出現的錯誤:

    -[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. 
    

這裏是我的項目的相關代碼:

此代碼可能會更容易在這個要點如下: 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]; 
} 

最下面兩個方法僅用於更新UI,以便我可以看到會發生什麼。

  • 要更改文件的內容,我刪除現有的fileWrapper並添加一個新的文件夾。這是我發現改變文件內容的唯一方法,以及我在其他SO答案中看到它完成的方式。

  • 當文檔被從磁盤加載,我把fileWrapper身邊,所以我可以用它(被稱爲myWrapper在上面的代碼)

蘋果的文檔說NSFileWrapper支持延遲加載和增量保存,所以我假設我的代碼有一些我看不到的基本缺陷。

+0

您的文檔是否支持版本控制? – 2013-10-07 15:45:35

+0

我不確定,所以我認爲不是:)我沒有做任何事情來支持它。它會改變什麼嗎?我將在以後看看 –

+1

由於我使用NSDocument設置,因此我支持版本控制。我試過把它關掉,但結果是一樣的 –

回答

1

NSFileWrapper本質上是一個unix文件節點的包裝。如果文件被移動,包裝保持有效。

喲似乎有問題是在保存過程中創建一個新的文件包裝是一個新的文件夾。系統刪除您以前的包裝,包括sub2

爲了達到您想要的效果,您需要更改爲增量保存,即只保存已更改的零件。請參閱NSDocument中的「保存」。

1

在您的-fileWrapperOfType:error:方法中,嘗試構建一個新的文件包裝器,其中包含更改成員的新內容並引用未修改成員的舊文件包裝器。

0

繼文檔addFileWrapper:您添加子(子目錄)給它,意味着

目錄/

  1. addfileWrapper:FILENAME1 目錄/文件名1/

  2. addfileWrapper:文件名2 directory/fileName1/fileName2。 該文件不存在。

你必須使用 addRegularFileWithContents:preferredFilename: 代替。