I have a saveMOC
which is the direct parent of a mainMOC
, and I need for online fetch another tmpMOC
in order not to block my UI whilst fetching a ton of records from the Internet.
My app freezes. I could narrow it to this very point:
fetchedItems = [tmpMOC executeFetchRequest:fetchRequest error:&error];
I tried to enclose this within dispatch_sync
, [moc.parentcontext.parentcontext.persistentStoreCoordinator lock/unlock]
, [whatevermoc performBlockAndWait]
...
I also try to fetch the _mainMOC
... No way...
I understand that executeFetchRequest
is not thread safe, so, how do I lock whatever I need to lock to get sure I am not inserting a double?
Anybody could help?
UPDATE (1)
_saveMOC
instantiation in AppDelegate:
- (NSManagedObjectContext *)managedObjectContext
{
if (_mainMOC != nil) {
return _mainMOC;
}
if (_saveMOC == nil) {
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
_saveMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_saveMOC setPersistentStoreCoordinator:coordinator];
[_saveMOC setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
}
}
if (_mainMOC == nil) {
_mainMOC = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_mainMOC setParentContext:_saveMOC];
[_mainMOC setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(saveContextChanges:) name:NSManagedObjectContextDidSaveNotification object:_mainMOC];
temporaryMOC
creation in MainViewController:
NSManagedObjectContext *temporaryContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
temporaryContext.parentContext = _mainMOC;
[temporaryContext performBlock:^{ //AndWait
NSError *error=nil;
Feed *feed=(Feed *)[temporaryContext existingObjectWithID:feedID error:&error];
//...
[RSSParser parseRSSFeedForRequest:req success:^(NSArray *feedItems)
{
NSLog(@"[MasterViewController::fetchPosts] inserting %d Posts.../OK", (int)[feedItems count]);
feed.valid = [NSNumber numberWithBool:YES];
for(RSSItem *i in feedItems)
{
[self createPostInFeed:feed withTitle:i.title withContent:(i.content?i.content:i.itemDescription) withURL:[i.link absoluteString] withDate:(i.pubDate?i.pubDate:[NSDate date]) inMOC:temporaryContext];
}
[[NSNotificationCenter defaultCenter] postNotificationName:@"NewPostsFetched" object:f];
Then the freeze happens in createPostInFeed
:
// @synchronized(fetchRequest) { // THIS DOESN'T CHANGE ANYTHING
// [moc.persistentStoreCoordinator lock]; // THIS NEITHER
NSArray *fetchedItems;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *ent = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:moc];
fetchRequest.entity = ent;
fetchRequest.propertiesToFetch = [NSArray arrayWithObjects:@"title", @"url", @"feed.name", nil];
[fetchRequest setResultType:NSDictionaryResultType];
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"title == %@ AND url == %@ AND feed.rss == %@", title, url, feed.rss];
NSError *error = nil;
fetchedItems = [moc executeFetchRequest:fetchRequest error:&error]; // FREEZES HERE
// [moc.persistentStoreCoordinator unlock]; // THIS DOESN'T CHANGE ANYTHING
// } // Synchronized neither...
Update (2): Here's what the Time Profiler sees.
Update (3): Block edited:
NSUInteger fetchedItems;
NSString *feedRSS=feed.rss;
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *ent = [NSEntityDescription entityForName:@"Post" inManagedObjectContext:moc];
fetchRequest.entity = ent;
fetchRequest.predicate = [NSPredicate predicateWithFormat:@"title == %@ AND url == %@ AND feed.rss == %@", title, url, feedRSS];
NSLog(@"MainViewController::createPostInFeed> Before fetchRequest for %@ (%@)", title, url);
NSError *error = nil;
fetchedItems = [moc countForFetchRequest:fetchRequest error:&error];
NSLog(@"MainViewController::createPostInFeed> After fetchRequest for %@ (%@)", title, url); // THIS NSLOGGING NEVER HAPPENS
Update (4): New profiler pic with call tree inverted.