简体   繁体   中英

CoreData crash with main queue context set as child of private queue context

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;
}

When I perform such fetch:

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]];

it crashes with this 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;
}

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?

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.

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 NSManagedObjectContext is:

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.

And with parent-child :

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM