【问题标题】:NSFileWrapper returns nil, sometimesNSFileWrapper 有时返回 nil
【发布时间】:2012-10-06 08:39:02
【问题描述】:

我将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: 但是 在 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;
}

【问题讨论】:

  • 这是一个疯狂的猜测,但我想知道聚光灯是否在您保存后修改文件属性(例如重新索引文件或其他内容)?我有点好奇你为什么在失败后保存;为什么不重新打开它呢?只是猜测尝试给你一些想法。
  • 猜测,但我认为您的对象已被释放。也许分配器出了点问题。你试过分析吗?小心 alloc 和 init(以及 self. + autorelease 和 release)。

标签: macos cocoa nsdocument nsfilewrapper


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

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

    来自Working with File Wrappers Apple 文档。

    请注意该部分的介绍:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多