“另存为”对我的NSPersistentDocument应用程序不起作用

时间:2014-06-09 13:07:37

标签: macos core-data osx-mavericks nspersistentdocument

我有一个OS X应用程序,它使用NSPersistentDocument的子类来存储数据。 Core Data持久性存储类型是SQLite。我依赖于在Xcode中使用Core Data为基于文档的应用程序创建新项目时创建的标准菜单命令。

此应用程序现在存在了大约两年,并且不断发展。就在今天,我发现"另存为"在我的最新版本中不起作用。行为如下:

  • 我创建了一个新文档并输入了一些数据。
  • 我保存文档,关闭它,然后重新打开它。一切都好。 然后我选择"另存为",选择文件的新名称和位置。 它被重命名,我可以输入更多数据。
  • 我保存文件,关闭它,重新打开它,它完全是空的。
  • 当我打开原始文档时,应该在保存文档中的所有更改都在那里。
  • 应用程序不会崩溃或产生任何错误。

我很确定它曾经正常运作。我试过了第一个"官方"我的程序的版本,行为是相同的(错误的)。

编辑:我创建了一个相同类型的新Xcode项目,只有一个Core Data实体。行为是一样的。与我的应用程序的唯一区别是新项目自动使用新的"复制"菜单命令是与10.7 Lion一起引入的,而不是"另存为"。所以我必须按Option键选择"另存为"。

我只在10.9.3上测试过,但在两台不同的Mac上测试过。有没有人知道在哪里看?

编辑2 :它似乎与特定帐户(我在两台计算机上的帐户)相关。它可以在另一个帐户上正常运行。

3 个答案:

答案 0 :(得分:1)

我们看到了类似的问题,但仅针对一些用户 - 我们比较了两台机器之间的堆栈跟踪 - 一方面有效,另一方则没有,我们可以看到存在差异。在工作方法上,writeSafely方法使用临时文件,但在非工作版本上不使用临时文件。

这种差异似乎发生在NSDocument的私有方法中,由于某种原因决定不使用临时文件夹。

我们发现如果我们覆盖这个私有方法并将forceTemporaryFile的值设置为YES,那么问题就会消失。

我们不想覆盖这个私有方法,因为我们需要提交到应用商店 - 但这可能对您有用吗?

答案 1 :(得分:1)

对我们来说,虚假行为甚至也出现在二元存储中(我们在应用程序中使用sqlite)。因此,我不认为DTS答案中提到的变化是同一个问题。 (我们目前正在构建10.8-SDK)。此外,这只发生在一些机器上,幸运的是我们现在可以访问它破坏的机器。

对于未记录的方法,覆盖

- (BOOL)_writeSafelyToURL:(NSURL*)url ofType:(NSString*)type forSaveOperation:(NSSaveOperationType)operation forceTemporaryDirectory:(BOOL)forceTemporary error:(NSError **)error
{
    return [super _writeSafelyToURL:url ofType:type forSaveOperation:operation forceTemporaryDirectory:YES error:error];
}

总是对forceTemporaryDirectory使用YES: - 参数解决了发生错误的机器上的问题。不建议实际使用,这只是在试图找到问题的原因时。

我也向cocoa-dev-mailing列表发了一个问题:http://lists.apple.com/archives/cocoa-dev/2014/Jun/msg00358.html也许某人有更多的信息。

答案 2 :(得分:0)

Felix Franz在cocoa-dev邮件列表上使用his posting让我走上了正确的轨道:问题与特定的ACL设置有关。我将以下代码添加到NSPersistentDocument类中以覆盖writeToURL:ofType:forSaveOperation:originalContentsURL:error:

- (BOOL)writeToURL:(NSURL *)absoluteURL ofType:(NSString *)typeName forSaveOperation:(NSSaveOperationType)saveOperation originalContentsURL:(NSURL *)absoluteOriginalContentsURL error:(NSError *__autoreleasing *)error {
    if ((saveOperation == NSSaveAsOperation)  && (absoluteOriginalContentsURL == nil)) {
        NSLog(@"---------- absoluteOriginalContentsURL == nil for NSSaveAsOperation ------------");
        return [super writeToURL:absoluteURL ofType:typeName forSaveOperation:saveOperation originalContentsURL:self.fileURL error:error];
    }
    return [super writeToURL:absoluteURL ofType:typeName forSaveOperation:saveOperation originalContentsURL:absoluteOriginalContentsURL error:error];
}

很明显,当self.fileURL由于某种原因为零时,它为超级方法提供absoluteOriginalContentsURL。现在"另存为"适用于我测试的所有帐户。