Core-Data executeFetchRequest freezes App in a background thread

I have asaveMOCwhich is the direct parent of amainMOC, and I need for online fetch anothertmpMOCin 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 withindispatch_sync,[moc.parentcontext.parentcontext.persistentStoreCoordinator lock/unlock],[whatevermoc performBlockAndWait]...

I also try to fetch the_mainMOC... No way...

I understand thatexecuteFetchRequestis 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)_saveMOCinstantiation 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];

temporaryMOCcreation 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 increatePostInFeed:

// @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.Core-Data executeFetchRequest freezes App in a background thread


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.Core-Data executeFetchRequest freezes App in a background thread

What is your goal withcreatePostInFeed? You show that you are doing a fetch but what do you do with that fetch? Is this a "insert or update" check? or is it just a "insert or skip" test?

Any fetch is going to lock theNSPersistentStoreCoordinatorand cause your application topotentiallylock up while the fetch is being performed. There are ways to mitigate that:

  1. Run Instruments
  2. Make your fetches more efficient
  3. If you don't need objects (in a insert or skip test) then do a count instead
  4. Fetch on a background queue and make sure your main MOC has all the objects it needs to avoid a lock

What does your instruments profile show you?

What doescreatePostInFeeddo with the results of that fetch?

What Others Are Reading