9

我正在使用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似乎谈到了这个问题:

如果用户在调用 readFromURL:options:error: 或 initWithURL:options:error: 之后但在 NSFileWrapper 读取文件内容之前修改了文件,则此方法可能返回 nil。使用 NSFileWrapperReadingImmediate 读取选项来降低出现该问题的可能性。

但我不明白在上面的代码中必须改变什么来防止这种情况。

失败的实验

如果返回 nil,我尝试保存文档,regularFileContents但之后仍然返回 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;
}
4

2 回答 2

4

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

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

于 2013-02-03T02:24:38.157 回答
1

如果磁盘上的文件发生更改,那么您将得到 nil (正如@Gene 所说)。但是,您可以使用以下matchesContentsOfURL:方法进行检查:

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

这来自使用文件包装器Apple 文档。

请注意该部分的介绍:

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

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

matchesContentsofURL:当您看到 nil 结果时,听到返回的内容很有趣。

于 2013-02-05T04:31:11.600 回答