【发布时间】:2014-03-30 05:04:18
【问题描述】:
我在这里碰壁了,我正在使用 Core Data 作为 SQLLite DB,并且我能够成功地保存到数据库中(我已经在离线 SQLLite 浏览器中检查了内容),但是保存第一个查询后,我尝试运行返回以下错误,我在 Internet 上找不到与此特定错误相关的任何有用信息:
核心数据:错误:-executeRequest:遇到异常= 数据库出现损坏。 (无效的主键)与 userInfo = { NSFilePath = "/Users/user/Library/Application Support/iPhone Simulator/7.0.3/Documents/db.sqlite";
这里的问题是导致此错误的原因,因为我找不到任何相关信息。
对于一些背景知识,这是我的设置,请假设我对所做的设计有充分的理由,并且不提供“更改你的设计”的答案,除非你能看到一些根本上被破坏的东西模式本身。
我有 3 个托管对象上下文,它们都是 NSPrivateQueueConcurrencyType,第一个 (A) 附加到 Persistent Store Coordinator,第二个 (B) 将 A 设置为其父上下文,第三个 (C) 具有 B设置为它的父上下文——一个链。这样做的原因是C是可写上下文,从网络源获取数据并同步保存,B是UI元素共享的上下文,我希望它是响应式的,最后A是设计的后台上下文卸载上下文 B 和 C 中保存到磁盘的任何延迟
PSC
如果我采取最后一步(将 A 保存到 PSC),那么应用程序运行良好,将所有内容保存在内存中并查询内存中的上下文。崩溃仅在我添加保存步骤后发生,并且仅在保存后对数据库运行的第一个查询中发生。我的 Save 和我的 fetch 执行都包含在 performBlock 中:
这是最后的存档:
- (void)deepSave
{
// Save to the Save Context which happens in memory, so the actual write to disk operation occurs on background thread
// Expects to be called with performBlock
NSError *error = nil;
[super save:&error];
NSAssert(!error, error.localizedDescription);
// Trigger the save context to save to disk, operation will be queued and free up read only context
NSManagedObjectContext *saveContext = self.parentContext;
[saveContext performBlock:^{
NSError *error = nil;
[saveContext save:&error];
NSAssert(!error, error.localizedDescription);
}];
}
这里是执行堆栈(在 NSManagedObjectContext 队列线程上)
#0 0x0079588a in objc_exception_throw ()
#1 0x079d98e7 in -[NSSQLiteConnection handleCorruptedDB:] ()
#2 0x078d9b8d in -[NSSQLiteConnection fetchResultSet:usingFetchPlan:] ()
#3 0x078e24a5 in newFetchedRowsForFetchPlan_MT ()
#4 0x078cd48e in -[NSSQLCore newRowsForFetchPlan:] ()
#5 0x078cca8d in -[NSSQLCore objectsForFetchRequest:inContext:] ()
#6 0x078cc53f in -[NSSQLCore executeRequest:withContext:error:] ()
#7 0x078cbf62 in -[NSPersistentStoreCoordinator executeRequest:withContext:error:] ()
#8 0x078c96c6 in -[NSManagedObjectContext executeFetchRequest:error:] ()
#9 0x0791e526 in -[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:] ()
#10 0x0799c1f4 in __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke ()
#11 0x0791e321 in internalBlockToNSManagedObjectContextPerform ()
#12 0x013c34b0 in _dispatch_client_callout ()
#13 0x013b0778 in _dispatch_barrier_sync_f_invoke ()
#14 0x013b0422 in dispatch_barrier_sync_f ()
#15 0x0791e2a2 in _perform ()
#16 0x0791e14e in -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] ()
#17 0x078c96c6 in -[NSManagedObjectContext executeFetchRequest:error:] ()
#18 0x0791e526 in -[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:] ()
#19 0x0799c1f4 in __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke ()
#20 0x0791e321 in internalBlockToNSManagedObjectContextPerform ()
#21 0x013c34b0 in _dispatch_client_callout ()
#22 0x013b0778 in _dispatch_barrier_sync_f_invoke ()
#23 0x013b0422 in dispatch_barrier_sync_f ()
#24 0x0791e2a2 in _perform ()
#25 0x0791e14e in -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:] ()
#26 0x078c96c6 in -[NSManagedObjectContext executeFetchRequest:error:] ()
【问题讨论】:
-
这种情况发生的唯一情况是您的数据库中的某一行的 z_pk=0。识别该行并确定它的创建位置将是调试的第一步。
-
@ImHuntingWabbits -- 我在 SQLLite 浏览器中打开了数据库,在崩溃时只有一个实体表中有数据(我正在运行查询的实体) 并且它具有正常的、顺序的 Z_PK 值,从 1 开始:(
-
在这种情况下,线程可能是罪魁祸首,但适当使用 performBlock 应该可以解决这个问题。此时,这些行是直接从 SQLite API 读取的,因此当 CoreData 说数据库已损坏时,它几乎不可能撒谎。如果您使用的是 WAL 模式,请尝试将其关闭(切换到删除日志模式)并重复您的测试。如果失败,您应该能够找到有问题的行。
-
@ImHuntingWabbits 你能看看我找到的解决方案吗? stackoverflow.com/a/22108189/285694
-
有一个根本问题,子上下文不是为线程设计的。
标签: ios objective-c sqlite core-data nsmanagedobjectcontext