我有报告称用户在通过App Store更新后无法使用iOS应用程序,因为Core Data使用的SQLite数据库显然已成为只读状态。这发生在读/写持久性存储中,该存储保存在应用程序包的Documents
文件夹中。
持久存储是在第一次登录应用时为每个用户从头开始创建的。其内容通过自定义渐进式管理对象模型迁移进行维护。碰巧的是,最近的版本没有迁移,因此应用程序启动后应该可以立即打开持久存储。
我们从用户收到的错误是相同的,它在升级完成后的流程启动早期发生。 userInfo
对象的NSError
就是我们在这种情况下捕获的内容:
NSSQLiteErrorDomain = 264;
NSUnderlyingException = "error during prepareSQL for SQL string 'SELECT Z_VERSION, Z_UUID, Z_PLIST FROM Z_METADATA' : attempt to write a readonly database";
由于我们正在记录的内容以及我们如何管理日志文件存在一些缺点,因此我不确切地知道在打开持久性存储的过程中何时发生这种情况。我们正在使用UIManagedDocument
但不通过iCloud共享任何文档。我假设在打开现有文档包时发生错误,但即便如此。 (因此,我对未来版本的日志记录进行了改进。)
我最接近再现错误的是使用iOS模拟器应用安装的文档包中的persistentStore-shm
文件上的文件权限0444,然后使用{尝试SELECT
语句{1}}命令行界面。在这种情况下的错误是sqlite3
而不是SQLITE_CANTOPEN
,所以我可能没有关于文件权限的理论。据我所知,SQLITE_READONLY
无论如何都会自动修复文件权限。
我想知道的是,是否有人经历过类似的行为?如果是这样,有没有办法恢复,以便用户不必完成重新创建本地数据存储的过程?
答案 0 :(得分:2)
我跑到这里,这很令人费解。事实证明,-shm文件,即预写日志的索引已被清除,需要重建。当将持久性存储加载到NSPersistentStoreCoordinator
时,这似乎会自动发生。
如果您在执行此操作之前致电+[NSPersistentStore metadataForPersistentStoreWithURL:error:]
,我将会收到您报告的错误,并且返回值为nil
。
因此,对我有用的解决方案是尝试检索元数据,如果失败并出现错误,则将持久存储加载到NSPersistentStoreCoordinator
以重建-shm。执行此操作后,调用metadataForPersistentStoreWithURL:error:
将返回元数据,而不会发出只读错误。
答案 1 :(得分:1)
在选项中添加您自己的描述符,以(重新)启用历史记录跟踪...
在将商店作为容器设置的一部分加载之前执行以下操作:
let container = NSPersistentContainer(name: "YourDataStoreIdentifier" )
let description = container.persistentStoreDescriptions.first
// This allows a 'non-iCloud' sycning
// container to keep track of changes
// as if it was an iCloud syncing container
description?.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
container.loadPersistentStores(...