title: Writing to coredata, even when done on background thread , blocks the UI considerably
body: <p>Iam trying out a chat based app. I have setup a singleton coredata manager as follows </p>
  
  <pre><code>#import "CGSharedCoreData.h"
  CGSharedCoreData *_cd;
  
  
  @implementation CGSharedCoreData
  
  @synthesize managedObjectModel = managedObjectModel_;
  @synthesize managedObjectContext = managedObjectContext_;
  @synthesize persistentStoreCoordinator = persistentStoreCoordinator_;
  
  
  + (CGSharedCoreData *)sharedCoreData{
      static CGSharedCoreData *_cd = nil;
      static dispatch_once_t onceCoreDataShared;
      dispatch_once(&amp;onceCoreDataShared, ^{
          _cd = [[CGSharedCoreData alloc] init];
      });
      return _cd;
  }
  
  
  + (void)saveContext:(NSManagedObjectContext*)c{
  
      @try {
  
  
          if (c.persistentStoreCoordinator.persistentStores.count == 0)
          {
              // This is the case where the persistent store is cleared during a logout.
              CGLog(@"saveContext: PersistentStoreCoordinator is deallocated.");
              return;
          }
  
  
          // Register context with the notification center
          NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
          CGSharedCoreData *sharedCoreData = [CGSharedCoreData sharedCoreData];
  
          [nc addObserver:sharedCoreData
                 selector:@selector(mergeChanges:)
                     name:NSManagedObjectContextDidSaveNotification
                   object:c];
  
  
          NSError *error = nil;
          if (c != nil) {
              CGLog(@"thread  &amp;&amp;*&amp;(*(* %d",[NSThread isMainThread]);
              if ([c hasChanges] &amp;&amp; ![c save:&amp;error]) {
                  CGLog(@"Unresolved error %@, %@", error, [error userInfo]);
              }
          }
  
          [nc removeObserver:sharedCoreData name:NSManagedObjectContextDidSaveNotification
                      object:c];
  
      }
  
      @catch (NSException *exception) {
          CGLog(@"***** Unresolved CoreData exception %@", [exception description]);
      }
  
  }
  
  
  + (dispatch_queue_t) backgroundSaveQueue
  {
      static dispatch_queue_t coredata_background_save_queue;
  
      static dispatch_once_t onceToken;
      dispatch_once(&amp;onceToken, ^{
          coredata_background_save_queue = dispatch_queue_create("com.shashank.coredata.backgroundsaves", NULL);
      });
  
      return coredata_background_save_queue;
  }
  
  
  + (void)performInTheBackground:(void (^)(NSManagedObjectContext *blockContext))bgBlock {
  
      dispatch_async([CGSharedCoreData backgroundSaveQueue],
      ^{
          NSManagedObjectContext *newContext = [[NSManagedObjectContext alloc] init];
          [newContext setPersistentStoreCoordinator:CG_CORE_DATA.persistentStoreCoordinator]; // Create a managed object context
          [newContext setStalenessInterval:0.0];
          [newContext setMergePolicy:NSMergeByPropertyStoreTrumpMergePolicy];
  
          bgBlock(newContext);
  
      });
  }
  
  - (void)saveContext {
      [CGSharedCoreData saveContext:managedObjectContext_];
  }
  
  - (void)clearStore {
  
      NSError *error = nil;
  
      if  (self.persistentStoreCoordinator) {
          if ([persistentStoreCoordinator_ persistentStores] == nil) {
              CGLog(@"No persistent stores to clear!");
          }
          else {
              CGLog(@"Cleaning persistent stores!");
  
              managedObjectContext_ = nil;
  
  
              NSPersistentStore *store = [[persistentStoreCoordinator_ persistentStores] lastObject];
  
              if (![persistentStoreCoordinator_ removePersistentStore:store error:&amp;error]) {
                  CGLog(@"Unresolved error %@, %@", error, [error userInfo]);
                  abort();
              }
  
              // Delete file
              if ([[NSFileManager defaultManager] fileExistsAtPath:store.URL.path]) {
                  if (![[NSFileManager defaultManager] removeItemAtPath:store.URL.path error:&amp;error]) {
                      CGLog(@"Unresolved error %@, %@", error, [error userInfo]);
                      abort();
                  }
              }
  
              // Delete the reference to non-existing store
              persistentStoreCoordinator_ = nil;
          }
      }
  }
  
  #pragma mark - Core Data stack
  
  // Returns the managed object context for the application.
  // If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application.
  - (NSManagedObjectContext *)managedObjectContext
  {
       NSAssert([NSThread isMainThread], @"Must be instantiated on main thread.");
  
      if (managedObjectContext_ != nil) {
          return managedObjectContext_;
      }
  
      NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
      if (coordinator != nil)
      {
          managedObjectContext_ = [[NSManagedObjectContext alloc] init];
          [managedObjectContext_ setPersistentStoreCoordinator:coordinator];
          [managedObjectContext_ setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
      }
  
      return managedObjectContext_;
  }
  
  // Returns the managed object model for the application.
  // If the model doesn't already exist, it is created from the application's model.
  
  - (NSManagedObjectModel *)managedObjectModel
  {
  
      if (managedObjectModel_ != nil) {
          return managedObjectModel_;
      }
  
      managedObjectModel_ = [NSManagedObjectModel mergedModelFromBundles:nil];
      return managedObjectModel_;
  }
  
  // Returns the persistent store coordinator for the application.
  // If the coordinator doesn't already exist, it is created and the application's store added to it.
  - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
  
      if (persistentStoreCoordinator_ != nil) {
          return persistentStoreCoordinator_;
      }
  
      CGLog(@"Creating a persistent store!");
  
      NSURL *storeURL = [NSURL fileURLWithPath: [[self applicationLibraryDirectory] stringByAppendingPathComponent: @"CGChatData.sqlite"]];
  
      NSError *error = nil;
      persistentStoreCoordinator_ = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
      if (![persistentStoreCoordinator_ addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&amp;error]) {
  
  
  
          CGLog(@"Unresolved error %@, %@", error, [error userInfo]);
          //        abort();
          CGLog(@"Delete STORE: %d",[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]);
          persistentStoreCoordinator_ = nil;
          persistentStoreCoordinator_ = self.persistentStoreCoordinator;
          }
  
      return persistentStoreCoordinator_;
  }
  
  #pragma mark -
  #pragma mark Handling Multiple Contexts
  
  /**
   Merges the changes from the insert contexts to the main context on the main thread.
   */
  
  - (void)mergeChanges:(NSNotification *)notification
  {
      // Merge changes into the main context on the main thread
      if(![[CGLoginEngine sharedLoginEngine] isLoggedIn])
          return;
  
      if (![NSThread isMainThread])
      {
          [self performSelectorOnMainThread:@selector(mergeChanges:)
                                 withObject:notification waitUntilDone:YES];
          return;
      }
  
      //CAUTION: Without the for clause below the NSFetchedResultsController may not capture all the changed objects.
      //For more info see: http://stackoverflow.com/questions/3923826/nsfetchedresultscontroller-with-predicate-ignores-changes-merged-from-different
      //and http://stackoverflow.com/questions/2590190/appending-data-to-nsfetchedresultscontroller-during-find-or-create-loop
  
  
      for (NSManagedObject *object in [[notification userInfo] objectForKey:NSUpdatedObjectsKey])
      {
          [[managedObjectContext_ objectWithID:[object objectID]] willAccessValueForKey:nil];
      }
  
  
      [managedObjectContext_ mergeChangesFromContextDidSaveNotification:notification];
  
  }
  </code></pre>
  
  <p>now , whenever i need to send a message , I am writing it to core data and updating the tableview with a fetched results controller. The writing part looks like this :</p>
  
  <pre><code>[CGSharedCoreData performInTheBackground:^(NSManagedObjectContext *blockContext)
           {
               CGLog(@"thread ******* is main %d",[NSThread isMainThread]);
              [[CGChatsModelController sharedChatModel] addChatWithtext:[chatMessage objectForKey:@"Message"]
                                                                                username:[chatMessage objectForKey:@"Receiver"]
                                                                               firstName:[chatMessage objectForKey:@"ReceiverFirstName"]
                                                                                lastName:[chatMessage objectForKey:@"ReceiverLastName"]
                                                                                 imageId:[chatMessage objectForKey:@"ReceiverImageID"]
                                                                             createdByMe:YES
                                                                                    time:time
                                                                                 context:blockContext];
                [CGSharedCoreData saveContext:blockContext];
  </code></pre>
  
  <p>But , When I send multiple messages in a very short span , it entirely blocks my UI, even when the core-data saving and all other related operations are being done on a background queue.
  Is there any particular reason for why ,this is happening ?  </p>
  
  <p>I am attaching a few other blocks of my code for reference here :</p>
  
  <pre><code>- (CGChat *) addChatWithtext:(NSString *)text username:(NSString *)username firstName:(NSString *)firstName lastName:(NSString *)lastName imageId:(NSString *)imageId createdByMe:(BOOL)yesOrNo time:(NSDate *)date context:(NSManagedObjectContext *)context
  {
      NSManagedObjectContext *backgroundContext = context;
      CGChat *chat = (CGChat *)[NSEntityDescription insertNewObjectForEntityForName:@"CGChat" inManagedObjectContext:backgroundContext];
      chat.text = text;
      chat.createdByMe = [NSNumber numberWithBool:yesOrNo];
  
  
       chat.status = @"sent";
  
  
      [self addChat:chat toUserWithUserName:username firstName:firstName lastName:lastName imageID:imageId time:date WithContext:backgroundContext];
  
      return chat;
  
  }
  
  - (CGChat *)lookUpChatWithUserName:(NSString *)username text:(NSString *)text timeStamp:(NSString *)timeStamp createdByMe:(BOOL) yesOrNo context:(NSManagedObjectContext *)context
  
  {
      NSFetchRequest *request = [[NSFetchRequest alloc] init];
  
      NSEntityDescription *entity = [NSEntityDescription entityForName:@"CGChat" inManagedObjectContext:context];
      [request setEntity:entity];
  
      NSPredicate *predicate = [NSPredicate predicateWithFormat:@"userIchatWith == %@ &amp;&amp; text == %@ &amp;&amp; timeStamp == %@ &amp;&amp; createdByMe ==%@", [self lookUpForUserWithUsername:username inContext:context],text,timeStamp,[NSNumber numberWithBool:yesOrNo]];
  
      [request setPredicate:predicate];
  
      NSArray *resultArray = nil;
      NSError *error;
  
      resultArray = [context executeFetchRequest:request error:&amp;error];
  
      CGChat *chat = nil;
      if ([resultArray count] &gt; 0) {
          chat  = [resultArray objectAtIndex:0];
      }
      return chat;
  
  }
  
  
  - (void) addChat:(CGChat *)chat toUserWithUserName:(NSString *)username firstName:(NSString *)firstName lastName:(NSString *)lastName imageID:(NSString *)imageId time:(NSDate *)date WithContext:(NSManagedObjectContext *)context
  
  {
  
      CGUser *user = [self lookUpForUserWithUsername:username inContext:context];
  
      if (!user)
      {
          user = (CGUser *)[NSEntityDescription insertNewObjectForEntityForName:@"CGUser" inManagedObjectContext:context];
          user.userName = username ;
  
  
      }
      user.firstName = firstName;
      user.lastName = lastName;
  
      if (![user.imageID isEqualToString:imageId])
      {
          user.imageID = imageId;
      }
  
  
      CGChat *chats = [self getLastChatForUsername:username andContext:context];
      if(chats)
      {
          chats.isLastChat = [NSNumber numberWithBool:NO];
      }
  
  
      NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
      [dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  
      chat.timeStamp = [dateFormat stringFromDate:date];
      chat.isLastChat = [NSNumber numberWithBool:YES];
      chat.userIchatWith = user;
      user.timeOfLatestChat = [dateFormat stringFromDate:date];
  
  }
  
  
  - (CGChat *) getLastChatForUsername:(NSString *)username andContext:(NSManagedObjectContext *)context
  {
  
      CGUser *user = [self lookUpForUserWithUsername:username inContext:context];
  
      if(user)
      {
          NSPredicate *predicate = [NSPredicate predicateWithFormat:@"isLastChat == %@",[NSNumber numberWithBool:YES]];
  
          NSSet *filteredSet = [user.chats filteredSetUsingPredicate:predicate];
  
          return [[filteredSet allObjects] lastObject];
      }
      else
      {
          return nil;
      }
  }
  
  
  - (CGUser *) lookUpForUserWithUsername:(NSString *)username inContext:(NSManagedObjectContext *)context
  {
      NSFetchRequest *request = [[NSFetchRequest alloc] init];
  
      NSEntityDescription *entity = [NSEntityDescription entityForName:@"CGUser" inManagedObjectContext:context];
      [request setEntity:entity];
  
      NSPredicate *predicate = [NSPredicate predicateWithFormat:@"userName == %@", username];
      [request setPredicate:predicate];
  
      NSArray *resultArray = nil;
      NSError *error;
  
      resultArray = [context executeFetchRequest:request error:&amp;error];
  
      CGUser *user = nil;
      if ([resultArray count] &gt; 0) {
          user  = [resultArray objectAtIndex:0];
      }
  
      return user;
  }
  </code></pre>