I am struggling with this for some time now and Apple's documentation and SO did not help so far. I was using ManagedObjectContext on a UIManagedDocument and the code below worked fine. I then decided to use Apple's template for CoreData in AppDelegate, so model, persistent store coordinator and context is created in AppDelegate. Fetching with AppDelegate's context is no problem, but background saving is an issue. I should have local context on the thread I am saving and as per Apple to have same persistance store coordinator. But the code below does not actually save the data. Can someone here please advise? Thank you.
- (void)fetchAndPersist
{
dispatch_queue_t ffetchQ = dispatch_queue_create("ForFetch", NULL);
dispatch_async(ffetchQ, ^{
NSManagedObjectContext *secureManagedObjectContext;
NSPersistentStoreCoordinator *coordinator = [appDelegate persistentStoreCoordinator];
if (coordinator != nil) {
secureManagedObjectContext = [[NSManagedObjectContext alloc] init];
[secureManagedObjectContext setPersistentStoreCoordinator:coordinator];
}
// find missing date
DataManager *dataManager = [[DataManager alloc] init];
NSDate *missingDate = [dataManager findMissingDateFromDate:selectedDate inContext:secureManagedObjectContext];
if (missingDate) {
// fetch and parse data
DataFetcher *dataFetcher = [[dataFetcher alloc] init];
NSDictionary *fetchResponse = [dataFetcher parseDataForDate:missingDate];
// persist it in a block and wait for it
[secureManagedObjectContext performBlock:^{
DataStore *dataStore = [[DataStore alloc] init];
BOOL parsingError = [dataStore persistData:fetchResponse inContext:secureManagedObjectContext];
if (parsingError) {
// handle error
} else {
dispatch_async(dispatch_get_main_queue(), ^{
// perform on main
[self fetchAndPersist];
});
}
}];
}
});
}
Try to use parent / child contexts:
http://www.cocoanetics.com/2012/07/multi-context-coredata/
In the link above you can find a code sample.
Your crash occurs because your NSManagedObjectContext
is using the older, obsolete thread confinement model for Core Data concurrency:
secureManagedObjectContext = [[NSManagedObjectContext alloc] init];
init
is just a wrapper around initWithConcurrencyType:
with the argument NSConfinementConcurrencyType
. This creates the context using the thread confinement model, which cannot use performBlock:
or performBlockAndWait:
. Only contexts using the newer (not obsolete!) queue confinement model can use these methods, and have to use these methods for any access to the context or objects belonging to it. To create a context using queue confinement and a private queue:
secureManagedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
If your code was migrated to using a private queue context you could also remove your serial dispatch queue, as the private queue context provides equivalent functionality.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With