【问题标题】:CoreData crash with main queue context set as child of private queue contextCoreData 崩溃,主队列上下文设置为私有队列上下文的子级
【发布时间】:2012-11-30 13:58:58
【问题描述】:

我的问题是这样的。我想异步保存到磁盘。设置核心数据堆栈的代码如下所示。

- (NSManagedObjectContext *)managedObjectContext {
NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    NSManagedObjectContext *privateMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    [privateMOC setPersistentStoreCoordinator:coordinator];
    __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [__managedObjectContext setParentContext:privateMOC];


});
return __managedObjectContext;
}

当我执行这样的获取时:

NSMutableArray *result = [NSMutableArray array];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:[DataObject entityName]
                                          inManagedObjectContext:self.managedObjectContext];

[request setEntity:entity];
[request setPredicate:[NSPredicate predicateWithFormat:@"SUBQUERY(threadEntities, $emp, $emp.thread = %@).@count>0 AND tags.@count!=0", self, nil ]];
[request setPropertiesToFetch:@[@"creationDate", @"data"]];
[request setSortDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"creationDate" ascending:YES]]];
NSError *error = nil;

[result addObjectsFromArray:[self.managedObjectContext executeFetchRequest:request error:&error]];

它会因为这个错误而崩溃:

Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 375961053 beyond bounds [0 .. 7]'

另一方面,这样的堆栈设置效果很好:

  - (NSManagedObjectContext *)managedObjectContext {
NSPersistentStoreCoordinator *coordinator = self.persistentStoreCoordinator;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    __managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    [__managedObjectContext setPersistentStoreCoordinator:coordinator];
});
return __managedObjectContext;
}

Database 内部有一个 DataObject 和一些用于管理它的附加对象。问题是,为什么这个 fetch 会受到影响,而应用程序之前使用相同参数执行的计数两次都有效?

【问题讨论】:

  • 让我有点恼火的是privateMOC__managedObjectContext创建后超出了范围。我不知道 MOC 是否强烈引用它的父上下文。如果没有,那么私有上下文可能会被释放,然后会发生奇怪的事情。 - 您可以尝试在实例变量中保留对 privateMOC 的强引用,看看是否有帮助。

标签: objective-c ios core-data concurrency


【解决方案1】:

看起来 CoreData 内部的某些内容变得不一致,就好像您也在处理错误的合并通知(使用父子时您不应该这样做,也不应该尝试!)。不幸的是,如果没有完整的堆栈跟踪,就很难重建这里发生的事情。

但是我没有看到在 dispatch_once 块内设置主队列上下文的原因。上下文是廉价的,没有理由每次你需要一个新的子上下文时不生成一个新的子上下文 - 这是使用它们的推荐方式。 NSManagedObjectContext是:

NSManagedObjectContext 的一个实例代表一个单一的“对象 空间”或应用程序中的便签本。它的主要职责是 管理托管对象的集合。这些对象形成一个组 表示内部一致视图的相关模型对象 一个或多个持久性存储。

还有parent-child:

当您在上下文中保存更改时,仅提交更改 “一个商店。”如果您保存子上下文,则更改将推送到其 父母。这些更改不会保存到持久存储中,直到 根上下文被保存。 (根托管对象上下文是 parent 为零。)此外,父级不会从 孩子们在它保存之前。如果需要,您必须保存子上下文 最终提交更改。

嵌套上下文使得采用 访问上下文的“传递接力棒”方法(通过传递上下文 从一个视图控制器到下一个)而不是检索它 直接来自应用程序委托。

如果您想看一个设置父子上下文和使用队列限制的简单示例: https://github.com/quellish/QueuedCoreData

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多