CoreData崩溃,并将主队列上下文设置为专用队列上下文的子级 [英] CoreData crash with main queue context set as child of private queue context

查看:103
本文介绍了CoreData崩溃,并将主队列上下文设置为专用队列上下文的子级的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My problems goes like this. I want to async saves to disk. The code to setup core data stack looks like this.

- (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]'

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

On the other hand stack setup like this works perfectly well:

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

数据库内部有一个DataObject和一些用于管理它的其他对象。问题是,为什么此获取会受到影响,而应用程序之前使用相同参数进行的计数却能同时工作两次?

Database has inside one DataObject and some additional objects used to manage it around. The question is, why this fetch is affected, while a count that app does before with same parameters works both times?

推荐答案

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

It looks like something inside CoreData is getting inconsistent, as if you were also processing a bad merge notification (which you shouldn't have to do when using parent child, and should not attempt!). Without a full stack trace unfortunately it would be pretty difficult to reconstruct what was going on here.

但是我看不到原因在dispatch_once块内设置您的主队列上下文。上下文很便宜,没有理由每次都不需要产生新的子上下文-这是使用它们的推荐方法。 NSManagedObjectContext 是:

However I don't see a reason to set up your main queue context inside the dispatch_once block. Contexts are made to be cheap, there is no reason not to produce a new child context every time you need one - and that is the recommended way to use them. An NSManagedObjectContextis:


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

An instance of NSManagedObjectContext represents a single "object space" or scratch pad in an application. Its primary responsibility is to manage a collection of managed objects. These objects form a group of related model objects that represent an internally consistent view of one or more persistent stores.

并带有父母/孩子


在上下文中保存更改时,更改只会提交
一间店。如果保存子上下文,则更改将推送到其
父对象。在保存
根上下文之前,这些更改不会保存到持久性存储中。 (根托管对象上下文是
父级为nil的上下文。)此外,父级在保存之前不会从
个子级中提取更改。如果您想最终
提交更改,则必须保存一个子上下文。

When you save changes in a context, the changes are only committed "one store up." If you save a child context, changes are pushed to its parent. These changes are not saved to the persistent store until the root context is saved. (A root managed object context is one whose parent is nil.) In addition, a parent does not pull changes from children before it saves. You must save a child contexts if you want ultimately to commit the changes.

嵌套上下文使采用
比以往任何时候都更加重要。 传递指挥棒的方法是访问上下文(通过将上下文
从一个视图控制器传递到下一个视图控制器),而不是直接从应用程序委托检索它

Nested contexts make it more important than ever that you adopt the "pass the baton" approach of accessing a context (by passing a context from one view controller to the next) rather than retrieving it directly from the application delegate.

如果要查看设置父子上下文并使用队列限制的简单示例:
https://github.com/quellish/QueuedCoreData

If you want to see a simple example of setting up parent-child contexts and using queue confinement: https://github.com/quellish/QueuedCoreData

这篇关于CoreData崩溃,并将主队列上下文设置为专用队列上下文的子级的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆