Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8553243
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 11, 20262026-06-11T14:36:26+00:00 2026-06-11T14:36:26+00:00

I have recently rewritten my Core Data driven database controller to use Grand Central

  • 0

I have recently rewritten my Core Data driven database controller to use Grand Central Dispatch to manage fetching and importing in the background. Controller can operate on 2 NSManagedContext’s:

  1. NSManagedObjectContext *mainMoc instance variable for main thread. this contexts is used only by quick access for UI by main thread or by dipatch_get_main_queue() global queue.

  2. NSManagedObjectContext *bgMoc for background tasks (importing and fetching data for NSFetchedresultsController for tables). This background tasks are fired ONLY by user defined queue: dispatch_queue_t bgQueue (instance variable in database controller object).

Fetching data for tables is done in background to not block user UI when bigger or more complicated predicates are performed.

Example fetching code for NSFetchedResultsController in my table view controllers:

-(void)fetchData{

dispatch_async([CDdb db].bgQueue, ^{

        NSError *error = nil;
        [[self.fetchedResultsController fetchRequest] setPredicate:self.predicate];
        if (self.fetchedResultsController && ![self.fetchedResultsController performFetch:&error]) {

            NSSLog(@"Unresolved error in fetchData %@", error);
        }

        if (!initial_fetch_attampted)initial_fetch_attampted = YES;
        fetching = NO;

        dispatch_async(dispatch_get_main_queue(), ^{

            [self.table reloadData];
            [self.table scrollRectToVisible:CGRectMake(0, 0, 100, 20) animated:YES];
        });

    });

} // end of fetchData function

bgMoc merges with mainMoc on save using NSManagedObjectContextDidSaveNotification:

- (void)bgMocDidSave:(NSNotification *)saveNotification {

    // CDdb - bgMoc didsave - merging changes with main mainMoc
    dispatch_async(dispatch_get_main_queue(), ^{

    [self.mainMoc mergeChangesFromContextDidSaveNotification:saveNotification];
     // Extra notification for some other, potentially interested clients
       [[NSNotificationCenter defaultCenter] postNotificationName:DATABASE_SAVED_WITH_CHANGES object:saveNotification];

    });
}

- (void)mainMocDidSave:(NSNotification *)saveNotification {

    // CDdb - main mainMoc didSave - merging changes with bgMoc
    dispatch_async(self.bgQueue, ^{
     [self.bgMoc mergeChangesFromContextDidSaveNotification:saveNotification];
     });
}

NSfetchedResultsController delegate has only one method implemented (for simplicity):

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {

    dispatch_async(dispatch_get_main_queue(), ^{

        [self fetchData];

    });

}

This way I am trying to follow Apple recommendation for Core Data: 1 NSManagedObjectContext per thread. I know this pattern is not completely clean for at last 2 reasons:

  1. bgQueue not necessarily fires the same thread after suspension but since it is serial, it should not matter much (there is never 2 threads trying access bgMoc NSManagedObjectContext dedicated to it).
  2. Sometimes table view data source methods will ask NSFetchedResultsController for info from bgMoc (since fetch is done on bgQueue) like sections count, fetched objects in section count, etc….

Event with this flaws this approach works pretty well of the 95% of application running time until …

AND HERE GOES MY QUESTION:

Sometimes, very randomly application freezes but not crashes. It does not response on any touch and the only way to get it back to live is to restart it completely (switching back to and from background does not help).
No exception is thrown and nothing is printed to the console (I have Breakpoints set for all exception in Xcode).

I have tried to debug it using Instruments (time profiles especially) to see if there is something hard going on on main thread but nothing is showing up.

I am aware that GCD and Core Data are the main suspects here, but I have no idea how to track / debug this.

Let me point out, that this also happens when I dispatch all the tasks to the queues asynchronously only (using dispatch_async everywhere). This makes me think it is not just standard deadlock.

Is there any possibility or hints of how could I get more info what is going on? Some extra debug flags, Instruments magical tricks or build setting etc…

Any suggestions on what could be the cause are very much appreciated as well as (or) pointers to how to implement background fetching for NSFetchedResultsController and background importing in better way.

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-11T14:36:27+00:00Added an answer on June 11, 2026 at 2:36 pm

    My first and very bad mistake was to fetch data for NSFetchedResultsController in the background queue.

    It turned out after testing, I was way too sensitive about fetching times. I unnecessary did put fetchData execution to back thread making core data related code too complex when the longest fetch time I could generate took literally split of a second. This introduced way too much complexity and uncertainty for very small performance gain (if any).

    I resigned form that by moving fetchData execution and all NSFetchedResultsControllerDelegate method to the main thread (simplified the code by removing GCD code).

    When this was done I no longer needed mainMocDidSave: and unregistered from listening to the NSManagedObjectContextDidSaveNotification for main thread context.
    I could also removed and unregistered DATABASE_SAVED_WITH_CHANGES notification posting.

    This greatly simplified ‘merging’ mechanism as from this time on only background thread context merges its changes with main thread context (when saved). Let’s call it one directional change notifications.

    NSFetchedResultsControllerDelegate methods will be fired automatically as they pickup main thread context changes after merge.

    Another important thing is to change dispatch_async to dispatch_sync in:

    - (void)bgMocDidSave:(NSNotification *)saveNotification {
    
        // CDdb - bgMoc didsave - merging changes with main mainMoc
            // Previously was: dispatch_async
            // dispatch_sync in this place may prevent from overlapping merging in some cases (many blocks in background queue)
        dispatch_sync(dispatch_get_main_queue(), ^{
    
        [self.mainMoc mergeChangesFromContextDidSaveNotification:saveNotification];
         // !!! Extra notification NO needed anymore
    
        });
    }
    

    Rule of thumb: SIMPLIFY and MINIMIZE amount of threads and NSManagedContexts.
    I experienced that having 2 contexts is enough even for very big apps:

    1. importContext operating in dedicated to GCD queue (MUST be serial queue). Just remember to save it at the end of the queue block’s code.
    2. mainConstext to operate on main UI thread (I call it READ context 😉 to be use when pulling data for the UI (presentation).
    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I have a piece of mature geospatial software that has recently had areas rewritten
I have a C# service application which interacts with a database. It was recently
Recently there have been a couple questions regarding static type constraints and inline: Use
I have recently merged together 5 of my stand-alone projects into one project to
I have recently had a linux server compromised from bots uploading .php scripts and
I have recently been working on implementing an ajax based file uploader for my
I have recently coded my button to be aligned to the right of the
I have recently upgraded my MVC 3 project to MVC 4. After all the
I have recently read topics about memory fragmentation: How to solve Memory Fragmentation and
I have recently began using C# to invoke powershell scripts, with some success :)

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.