NSFileWrapper有时会返回nil

时间:2012-10-16 09:21:57

标签: macos cocoa nsdocument nsfilewrapper

我正在使用NSFileWrapper作为我的包文档。有时,当我请求包中的文件数据时,我得到nil

这是我查询包中文件数据的方式:

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

此方法最终开始为某些文件(不是全部)返回nil。可悲的是,我没有设法一致地重现这个问题。

如果它有帮助,这就是我打开包装的方式:

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

这是我更新包内文件数据的方法:

- (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];
}

这是我保存包裹的方式:

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

为什么会这样?有没有办法阻止它?

regularFileContents的文档似乎谈到了这个问题:

  

如果用户在您之后修改文件,则此方法可能返回nil   调用readFromURL:options:error:或initWithURL:options:error:but   在NSFileWrapper读取文件内容之前。使用   NSFileWrapperReadingImmediate读取选项以降低可能性   那个问题。

但我不明白上面的代码中有什么需要改变以防止出现这种情况。

实验失败

如果regularFileContents返回nil,我尝试保存文档,但之后仍然返回nil。像这样:

- (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;
}

2 个答案:

答案 0 :(得分:3)

没有足够的代码来查看真正发生的事情。然而,根本原因是NSFileWrapper正如其名称所暗示的那样:表示文件或目录的对象。因此,实际文件或目录很容易与存在于内存中的对象“不同步”。只要NSFileWrapper确定发生了这种情况,它就会为某些操作返回nil。解决方案是使NSFileWrapper个对象短暂存在。只在您需要时创建并打开,然后尽快保存并关闭。

特别是,看起来你的代码长时间保持指向包目录包装器的指针,并假设它始终有效。如果目录因任何原因而更改,则情况并非如此。重新编码,以便每次需要时都获得一个新的包目录包装器,问题应该消失。

答案 1 :(得分:0)

如果文件在磁盘上发生变化,那么你将获得nil(正如@Gene所说)。但是,您可以使用matchesContentsOfURL:方法进行检查:

  

根据上次读取或写入文件时存储的文件属性,确定磁盘表示是否已更改。如果文件包装器的修改时间或访问权限与磁盘上文件的修改时间或访问权限不同,则此方法返回YES。然后,您可以使用readFromURL:options:error:

来自Working with File Wrappers Apple文档。

请注意该部分的介绍:

  

因为文件包装器的目的是表示内存中的文件,所以它与任何磁盘表示都非常松散地耦合。文件包装器不会记录其内容的磁盘表示的路径。这允许您使用不同的URL保存相同的文件包装器,但如果您想稍后从磁盘更新文件包装器,还需要您记录这些URL。

因此,如果您需要/需要重新阅读,您必须将网址保存到原始文件中。

有趣的是,当您看到无结果时,会听到matchesContentsofURL:返回的内容。