为什么将文件保存到NSDocument中会创建名称中包含奇怪字符的同一文件的版本?

时间:2014-02-26 15:34:20

标签: appkit nsdocument nsfilewrapper

我正在开发一个基于NSDocument的应用程序,其文档类型是包含一堆文件的包。我正在保存它:

- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
{
    if (!self.documentFileWrapper) {
        NSFileWrapper *documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
        [self setDocumentFileWrapper:documentFileWrapper];
    }

    NSFileWrapper *defaultWrapper = [self.documentFileWrapper.fileWrappers objectForKey:@"default"];
    if (!defaultWrapper) {
        defaultWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
        [defaultWrapper setPreferredFilename:@"someFile.ext"];
        [self.documentFileWrapper addFileWrapper:defaultWrapper];
    }

    [defaultWrapper addRegularFileWithContents: ... some computed content for the file ... preferredFilename:@"someFile.ext"];

    return self.documentFileWrapper;
}

换句话说,在包中创建一个文件夹“default”,并用一些内容将“someFile.ext”保存到其中。

现在,问题。当我查看实际保存在磁盘上的内容时,我看到了这一点:

screenshot

每次保存文件时,NSDocument包装器似乎都会创建一些版本的资源副本。我不想要版本化的克隆,我只想要带有最新内容的vanilla文件。

版本化资源来自哪里?这里发生了什么?我应该阅读一份文件吗?

2 个答案:

答案 0 :(得分:2)

好的,我想我已经明白了。事实证明,它实际上并不是版本问题。您似乎每次只是添加一个新文件。首先,请注意几点。

  1. 您似乎不是在包中创建文件,而是在包中创建“包含文件的目录”。那是你打算做的吗?
  2. 似乎如果目录“default”不存在,则创建并使用目录“someFile.ext”,这意味着下次它创建一个带有奇怪前缀的新目录。但是,我从截图中看到您已经有一个目录“default”,这意味着这不是您的问题。
  3. 现在,您的实际问题:根据this documentationaddRegularFileWithContents使用您首选的文件名创建一个新文件,除非目录(defaultWrapper)已包含具有该名称的文件(基本上)。如果已经存在,则会创建带有前缀的新文件。 addRegularFileWithContents返回一个引用创建的NSFileWrapper的标识字符串(我认为它是文件名)。

    所以,正在发生的事情是,每次你去保存文件时,它都会看到已有一个该名称的文件,并创建一个新的前缀文件。解决此问题的一种方法是保留由addRegularFileWithContents返回的NSString,然后当你去保存时检查defaultWrapper并删除与存储的NSString相关联的NSFileWrapper(如果有的话),然后添加文件就像正常一样。我修改了你的代码如下:

    @interface TestDocument () // Relevant part of my test class.  Note `wrapperFileName`.
    
    @property (nonatomic, strong) NSFileWrapper *documentFileWrapper;
    @property (nonatomic, strong) NSString *wrapperFileName;
    
    @end
    
    
    
    - (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
    {
        if (!self.documentFileWrapper) {
            NSFileWrapper *documentFileWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
            [self setDocumentFileWrapper:documentFileWrapper];
        }
    
        NSFileWrapper *defaultWrapper = [self.documentFileWrapper.fileWrappers objectForKey:@"default"];
        if (!defaultWrapper) {
            defaultWrapper = [[NSFileWrapper alloc] initDirectoryWithFileWrappers:nil];
            [defaultWrapper setPreferredFilename:@"default"];
            [self.documentFileWrapper addFileWrapper:defaultWrapper];
        } else if (self.wrapperFileName) {
            [defaultWrapper removeFileWrapper:[[defaultWrapper fileWrappers] objectForKey:self.wrapperFileName]];
        }
    
        self.wrapperFileName = [defaultWrapper addRegularFileWithContents:[@"blah blah" dataUsingEncoding:NSUTF8StringEncoding] preferredFilename:@"someFile.txt"];
        return self.documentFileWrapper;
    }
    
    1. 我已将defaultWrapper的首选文件名更改为“默认”,因为我怀疑你的意图。
    2. 我添加了if块,删除以前保存的文件(如果存在)。
    3. 我已经存储了新的NSFileWrapper的文件名,以便下次在#2中使用。
    4. 在这些更改之后,程序演示了我认为您期望的行为:一个目录包含一个文件,即使在多次保存之后也是如此。请注意,即使preservesVersions返回YES,也是如此。我不确定它存储版本的位置,但我没有看到它们。

答案 1 :(得分:1)

您可以实现-writeSafely ...以便直接调用-writeToURL:... 实现-writeToURL:...以便它调用-fileWrapperOfType:...然后将其写入URL 原子

即。你可以通过让NSFileWrapper做到这一点来接管原子保存的责任。这样包装器应该整齐地跟踪文件最终的位置。

Source