【问题标题】:NSFileWrapper, lazy loading and savingNSFileWrapper,懒加载和保存
【发布时间】:2013-10-14 06:21:56
【问题描述】:

我有一个基于 NSDocument 的应用程序,它使用文件包装器来保存和加载其数据。 文档可以有各种资源,所以我不想把所有的东西都加载到内存中。我可能做错了什么,但是一旦我更改了一个(内部)文件然后保存,我就无法读取任何尚未加载到内存中的文件。

我已将相关代码分离到一个单独的项目中以重现此行为,并且得到相同的结果。基本流程是这样的:

  • 我从磁盘加载现有文档。主文件包装器是一个目录文件包装器(我称之为main),其中包含另外两个文件包装器(sub1sub2)。此时,两个内部文件包装器加载。
  • 当用户想要编辑 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

Apple 文档说 NSFileWrapper 支持延迟加载和增量保存,所以我假设我的代码有一些我看不到的基本缺陷。

【问题讨论】:

  • 您的文档是否支持版本控制?
  • 我不确定,所以我认为不是 :) 我没有做任何事情来支持它。它会改变什么吗?稍后我会调查的
  • 当我使用 NSDocument 设置时,我支持版本控制。我试过关掉它,但结果是一样的
  • 您是否尝试过上苹果官方开发者论坛? IMAO,你会得到有经验的人。
  • @SevenBits IMAO 代表什么?

标签: objective-c macos cocoa nsdocument nsfilewrapper


【解决方案1】:

NSFileWrapper 本质上是一个 unix 文件节点的包装器。如果文件被移动,包装器保持有效。

您似乎遇到的问题是在保存期间创建新文件包装器是一个新文件夹。系统会删除您之前的包装器,包括 sub2

要实现您想要的,您需要更改为增量保存,即仅将更改的部分保存到位。请参阅 NSDocument 中的“原地保存”。

【讨论】:

    【解决方案2】:

    在您的 -fileWrapperOfType:error: 方法中,尝试构建一个新的文件包装器,其中包含更改成员的新内容并引用未更改成员的旧文件包装器。

    【讨论】:

      【解决方案3】:

      按照文档添加文件包装器:向其中添加子(子目录)意味着

      目录/

      1. addfileWrapper:fileName1 目录/文件名1/

      2. addfileWrapper:fileName2 目录/文件名 1/文件名 2。 该文件不存在。

      你必须使用 addRegularFileWithContents:preferredFilename: 而是。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-11-17
        • 2019-11-08
        • 1970-01-01
        相关资源
        最近更新 更多