核心数据存储损坏

20

我的iPhone应用的少数客户遇到了Core Data存储损坏的问题(我认为是这样,因为错误提示是“未能保存到数据存储:操作无法完成。(Cocoa错误259.)”)

有其他人经历过这种存储损坏吗?我很担心,因为我打算很快推出一个执行模式迁移的更新,我担心这将暴露更多的问题。

我曾认为Core Data / SQLlite API 使用原子操作,并且只有在底层文件系统发生故障时才会出现损坏。

是否有一种方法可以减少/防止损坏,以及重现损坏的方法,以便我可以测试(到目前为止我一直没有成功)。

编辑:

还出现了这个错误:“/var/mobile/Applications//Documents/foo.sqlite上的数据库已损坏。SQLite错误代码11,数据库磁盘映像格式不正确。”


2
还遇到了这个错误:“/var/mobile/Applications/<UUID>/Documents/foo.sqlite 数据库已损坏。SQLite 错误代码 11,数据库磁盘映像格式不正确。” - sehugg
看起来这可能是由于4.2和4.3中包含的SQLite库的更改引起的:https://devforums.apple.com/message/409734 - Hunter
我一直收到我的应用程序用户的类似报告,尤其是使用硬件性能较低的旧设备的用户。目前我唯一的解决方法是在检测到损坏的存储时将其删除、重新创建,然后从服务器重新填充数据,这远非最佳选择。 - Jiho Kang
还有一点需要注意的是,我有很多后台线程执行核心数据操作。这可能与旧设备不支持多任务处理有关,因为应用程序会立即被杀死。我在想当 applicationWillTerminate 被调用时,我的后台线程会发生什么。 - Jiho Kang
如果你的应用程序退出后,仍有线程在执行Core Data操作,那么可能会发生一些不好的事情。最好将你的操作放入NSOperationQueue中,并在应用程序退出时启动一个后台任务来处理未完成的操作——这样至少你还有几秒钟时间来完成所有操作。 - sehugg
我认为在WWDC会议视频中还有更多关于线程和Core Data的内容。 - sehugg
8个回答

22

当我手动覆盖Base.sqlite而没有删除Base.sqlite-walBase.sqlite-shm时,就会出现这种情况。实际上,这些文件是新的SQLite 3.7功能,可能在iOS 7中添加。

为了解决问题,我删除了Base.sqlite-*,然后sqlite从我的新基础版本重新生成了它们。


4
这篇文章帮助我解决了Core Data Migration期间的一个问题,即迁移后出现了-wal和-shm文件。这种情况下,我会收到数据库损坏的消息。由于数据库日志模式已设置为DELETE,因此这些文件实际上不应该存在。嗯,确保在设置持久化存储之前将它们删除就解决了问题。谢谢Martin。 - sckor

2

当我尝试获取持久化存储协调器时,遇到了这个错误。

在我的情况下,多线程是问题所在。通过将整个方法用@synchronized(self) {}块包装来解决问题。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    @synchronized(self) {

    // Quickly return persistent store coordinator if available
    if (__persistentStoreCoordinator != nil) {
        return __persistentStoreCoordinator;
    }

    // Persistent store coordination initialization, to be performed once
    // ...

    }
    return _persistentStoreCoordinator;
}

2
你所遇到的错误在Foundation.h中定义。
NSFileReadCorruptFileError = 259,//读取错误(文件损坏、格式错误等)
我从未在实际存储中遇到过这种情况,但在Mac上遇到了类似的权限问题。我也没有看到任何人在网上提到过类似的错误。Core Data中的错误预防系统相当强大。
我猜最容易创建这个错误的方法是发送持久存储来查看错误的文件,例如意外地将其定位到文本文件。如果它期望一个SQL存储但找到其他东西,它会抱怨文件已损坏。这只是一个猜测。
编辑
这将很难跟踪,因为像这样的错误在Core Data中非常罕见,没有任何工具可以帮助找到问题。
我建议:
1. 检查代码中错误发生的上游。也许某些东西会使存储出错或导致它查找另一个位置。
2. 检查您可能执行非标准操作的任何地方。例如,如果您在代码中生成自己的实体映射,如果不小心,很容易将其扔掉。

这可能会导致错误代码,但我需要找出这种损坏的根本原因 - 这很困难,因为它只影响少数用户。 - sehugg

2

尝试通过在设备上填充驱动器来复制错误--您应该收到磁盘已满的错误,而不是数据库损坏,但可能会以这种方式获得损坏的数据库。


+1 另一个好主意。满硬盘有时会引起奇怪的、看似无关的错误。 - TechZen
3
通常,空间不足的错误会显示“磁盘已满”的错误。但我遇到一个用户报告了“数据库磁盘映像损坏”的错误。他的手机显示还有1.5 GB以上的可用存储空间。重新安装(使用新的SQlite数据库)仍然显示相同的损坏错误。然后他清理了一些额外的存储空间,重新安装后,声称它开始工作了。我不知道磁盘是否是罪魁祸首,或者存储硬件在某些区域上出现故障并清理空间强制应用程序重新安装到另一个位置并开始工作。无论如何,让用户清理空间值得尝试。 - Protongun

2
为了清楚起见,本文使用Xcode 7.2.1、SQLite数据存储和Core Data对象图作为原型应用程序。我的问题由Xcode终端详细说明如下:

CoreData: error: (11) Fatal error. The database at /Users/etc/Library/Developer/CoreSimulator/Devices/etc/data/Containers/Data/Application/etc/Library/Application Support/com.etc.etc/etc.sqlite is corrupted. SQLite error code:11, 'database disk image is malformed'.

实际上,我的应用程序能够加载和读取SQLite数据,但无法保存。SO用户software evolved的这个答案对我有帮助。在使用模拟器时,我相当确定我已经中断了一个具有私有队列并发类型NSPrivateQueueConcurrencyType的托管对象上下文的保存操作。
进一步调查(使用SQLiteManager)揭示了我当时正在保存的SQLite表是这个问题的原因。我本可以轻松地删除该应用程序(尚未公开发布),但我想至少要理解如何修复这个问题。
从这次经历中得到的笔记:
  • 在应用程序委托下的UIApplicationDelegate协议 - (void)applicationWillResignActive:(UIApplication *)application中,如果您的托管对象上下文hasChanges,请确保包含一个数据库保存方法;
  • 如果使用多个队列,请在单击Xcode的停止按钮之前使用主页按钮触发第1项中的委托方法;
  • 修复损坏的数据库文件-我从Fixing the SQLite error “The database disk image is malformed”这个网页上概述的答案中开发了一个解决方案。

SQLite数据库文件修复方法:
  1. 打开终端 [终端/SQLite 命令];
  2. 导航到适当的文件位置 [cd];
  3. 为备份目的,复制“格式不正确”的数据库文件(例如 dbMalFormedBU.sqlite)(如果修复成功后可以删除)[cp];
  4. 确保删除 dbMalFormed.sqlite-shmdbMalFormed.sqlite-wal 文件 [rm];
  5. 打开您的“格式不正确”数据库文件 [sqlite3 dbMalFormed.sqlite];
  6. 克隆您的数据库文件 [.clone dbMalFormedNew.sqlite];
  7. 退出 SQLite3 [.exit];
  8. 删除旧的“格式不正确”的数据库文件 [rm dbMalFormed.sqlite]);
  9. 将新的数据库文件重命名为先前使用的名称 [mv dbMalFormedNew.sqlite dbMalFormed.sqlite]。

1
你是否曾使用sqlite API与数据库交互?或者你是否使用过非Apple工具来创建种子数据库?

+1 这是一个非常好的想法。我从来没有这样做过,所以我没有想到。然而,Core Data 对其存储非常挑剔。最小的错误都会导致它停止工作。 - TechZen
不,只是标准的Core Data东西,包括NSPersistentStoreCoordinatorNSManagedObjectModel等。 - sehugg

1

当我在一个分离的线程(非主线程)中预加载数据库时,我遇到了“Core Data存储损坏”的问题,这个bug很难找到,因为只有少数客户会因此而使他们的应用程序崩溃。


0

我最近遇到了这个问题。在我的情况下,我正在执行搜索并迭代对象以将数据转换为XML和KML。然后,我会生成电子邮件处理程序并附加文件。然后,我会更新对象中的字段,最后保存到后备存储(SQL Lite)。在3.x中运行良好,在4.x中出现了问题。

在修改和保存数据库之前处理所有非必要代码是我犯的愚蠢错误。将所有非必要代码移到保存后的位置可以解决此问题。

这个问题会完全破坏SQL数据库。在我的情况下,错误是:

 File at path does not appear to be a SQLite database

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接