1

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

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

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

我很确定它曾经正常工作。我尝试了我的程序的第一个“官方”版本,并且行为是相同的(错误的)。

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

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

编辑2:它似乎与特定帐户有关(我在两台机器上的帐户)。它在另一个帐户上正常工作。

4

3 回答 3

1

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

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

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

我们不想覆盖这个私有方法,因为我们需要提交到应用商店——但也许这对你有用?

于 2014-06-24T10:28:22.397 回答
1

对我们来说,二进制存储也会出现错误行为(我们在应用程序中使用 sqlite)。因此,我认为 DTS-answer 中提到的更改不是同一个问题。(我们目前针对 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:-参数解决了发生错误的机器上的问题。不建议实际使用,这只是在尝试查找问题原因时。

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

于 2014-06-25T08:21:15.370 回答
0

Felix Franz 在 cocoa-dev 邮件列表上的帖子让我走上了正轨:问题与特定的 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给 super 方法 when absoluteOriginalContentsURLis nil 出于某种原因。现在“另存为”适用于我测试的所有帐户。

于 2014-06-25T19:40:39.713 回答