使用 NSPersistentDocument 创建“文档”

Posted

技术标签:

【中文标题】使用 NSPersistentDocument 创建“文档”【英文标题】:Using NSPersistentDocument to create 'Documents' 【发布时间】:2017-07-27 16:13:26 【问题描述】:

我想创建一个使用

的应用程序 斯威夫特 核心数据 以标准 macOS 方式工作的“文档”[自定义扩展,包含与该文档相关的所有数据的单个“文件”/文件包装器]

这似乎是不可能的。文档非常清楚地指出

NSPersistentDocument 不支持某些文档行为: 文件包装器。 [..]

这让我想到了在 CoreData 中处理图像的常用方法 - 带有“允许外部存储”的二进制数据并将它们保存到不同的位置,将 URL 存储在数据库中 - 不能与 NSPersistentDocument 一起使用。我希望我的用户能够对我的“文件”执行通常的 Finder 操作(复制、移动到外部存储、从外部备份恢复)并且需要将我的所有数据放在一个包中。

文件存储的 SQL 版本在保存时会产生通常的三倍堆栈 - .sqlite、.sqlite-shm、.sqlite-wal - 作为“文档”是无用的。

有没有我忽略的解决方案? (示例非常少;Big Nerd Ranch sample 也没有解决这个问题;Marcus Zarra 和 Objc.io 都没有涉及 NSPersistentDocument)。

【问题讨论】:

【参考方案1】:

NSPersistentDocument 一起使用的唯一选项是将图像直接存储在数据库中。您需要实体上的二进制数据属性,但不能打开Allows External Storage 选项。

如果您打开此选项,Core Data 将根据大小决定是将图像直接存储在数据库中还是存储在文档所在文件夹内的隐藏文件夹中:

(我在 Finder 中输入 cmd-shift-. 使文件夹可见)。示例文档名为Test 1.doof,包含三张图片:

您可以看到隐藏文件夹.Test 1_SUPPORT/EXTERNAL DATA 包含两个文件,分别是两个较大的图像(1.3 MB 和 494 KB)。第三个只有 50 KB 存储在 Test 1.doof 中。如果您将Test 1.doof 移动到另一个文件夹中,隐藏的文件夹将被留下。在另一个文件夹中打开文件会导致两个图像丢失。

如果您将二进制数据放入与其余数据一对一关系的单独实体中,则将图像存储在数据库中并不是那么糟糕,如下所示:

这样图像就不会干扰任何搜索或排序操作。 NSPersistentDocument 为您免费提供了许多很酷的功能,因此您应该尽可能使用它。

两个补充说明:

如果您为某个属性打开Allows External Storage,您不必关心 URL 或存储图像的位置,Core Data 会为您执行此操作(但对于基于文档的应用程序而言不是一种有用的方式)。 这些shmwal 文件是“有时”出现的临时文件,对于没有外部存储的数据库也是如此。如果它们粘在上面,您可以在应用关闭时安全地移除它们。

【讨论】:

【参考方案2】:

如果您想在文档中添加更多内容而不仅仅是一个数据库,那么您应该实现NSDocument 而不是NSPersistentDocument。在这种情况下,您不会获得对 CoreData 的内置支持,但您可以将文档用作多种文件类型的容器。

另见Is NSDocument and CoreData a possible combination, or is NSPersistentDocument the only way?

【讨论】:

如何在文件包装器中创建单独的 CoreData 存储 (sql)?链接的示例为所有信息提出了一个单一的 CoreData 存储,各个文档使用不同类型的存储(plist 等) - 而我真的在寻找使用 CoreData 的“文档”。 您还可以在 NSDocument 范围内实例化 Core Data 堆栈,并将您的 SQLite、XML 或二进制文件保存在文档中。 如果包含 SQLite 文件的文档在打开时被移动到不同的目录,会破坏 Core Data 吗?我们是否需要检测文档被移动,拆除 Core Data 堆栈并重新创建它? @malhal 在大多数情况下,macOS 会自动跟踪在应用程序中打开时移动的文件。 我试了一下,然后在启动应用程序时重命名包含 SQLite 文件的文件夹,当尝试保存上下文时,CoreData 出现异常:错误:打开存储时出错:错误域 = NSPOSIXErrorDomain 代码 = 2“没有这样的文件或目录”,所以我的猜测是我们需要检测正在移动的文档并在其新位置重新创建核心数据堆栈,从而使这个线程安全可能是一场噩梦。

以上是关于使用 NSPersistentDocument 创建“文档”的主要内容,如果未能解决你的问题,请参考以下文章

NSPersistentDocument:浏览版本:尝试添加只读文件

撤消麻烦:以编程方式初始化`NSPersistentDocument`,标题栏中没有“已编辑”标志

如何在 XCTestCase 中测试 NSPersistentDocument?

NSPersistentDocument 和 NSArrayController 与 MagicalRecord

创建持久存储时 NSPersistentDocument 崩溃

在 NSPersistentDocument 上启用核心数据的自动轻量级迁移