title: Background Managed Object Context Staggers UI Animation
body: <p>I've got a doozey of a problem that I've been working on for a few weeks. It involves stuttering UI performance whenever I save my Core Data managed object context. I've gotten as far as I can on my own and am looking for some help.</p>
  
  <h1>The Situation</h1>
  
  <p>My application uses two <code>NSManagedObjectContext</code> instances. One belongs to the application delegate and has a persistent store coordinator attached to it. The other is a child of the main MOC and belongs to a <code>Class</code> object, called the <code>PhotoFetcher</code>. It uses <code>NSPrivateQueueConcurrencyType</code> so all operations performed on this MOC take place in a background queue.</p>
  
  <p>Our application downloads JSON data representing data about photographs from our API. In order to retrieve data from our API, the following sequence of steps takes place:</p>
  
  <ol>
  <li>Construct an <code>NSURLRequest</code> object and use the <code>NSURLConnectionDataDelegate</code> protocol to construct the data returned from the request, or handle errors.</li>
  <li>Once the download of the JSON data is complete, perform a block on the secondary MOC's queue that does the following:
  
  <ol>
  <li>Parse the JSON using <code>NSJSONSerialization</code> into Foundation class instances.</li>
  <li>Iterate over the parsed data, inserting or updating entities in my background context as needed. Typically, this results in about 300 new or updated entities.</li>
  <li>Save the background context. This propagates my changes to the main MOC.</li>
  <li>Perform a block on the main MOC to save <em>it's</em> context. This is to have our data persisted to disk, a <code>SQLite</code> store. Finally, make a callback to a delegate informing them that the response has been fully inserted into the Core Data store.</li>
  </ol></li>
  </ol>
  
  <p>The code to save the background MOC looks something like this:</p>
  
  <pre><code>[AppDelegate.managedObjectContext performBlock:^{
      [AppDelegate saveContext]; //A standard save: call to the main MOC
  }];
  </code></pre>
  
  <p>When the main object context saves, it's also saving a fair number of JPEGs that have been downloaded since the last time a main object context save occurred. Currently, on the iPhone 4, we're downloading 15 200x200 JPEGs at 70% compression, or about 2MB of data in total.</p>
  
  <h1>The Problem</h1>
  
  <p>This works, and works well. My problem is that once the background context saves, the <code>NSFetchedResultsController</code> running in my view controller picks up the changes propagated up to the main MOC. It inserts new cells in our <code>PSTCollectionView</code>, an open-source clone of <code>UICollectionView</code>. While it's inserting new cells, the main context saves and writes those changes to disk. This can take, on an iPhone 4 running iOS 5.1, anywhere from 250-350ms. </p>
  
  <p>During that third of a second, the app is completely unresponsive. Animations that were in progress before the save are paused and no new user events are sent to the main run loop until the save completes.</p>
  
  <p>I ran our app in Instruments using the Time Profiler to identify what is blocking our main thread. Unfortunately, the results have been rather opaque. This is the heaviest stack trace I get from Instruments.</p>
  
  <p><img src="https://i.stack.imgur.com/oT4E5.png" alt="Instruments Heaviest Stack Trace"></p>
  
  <p>It <em>appeared</em> to be saving updates to the persistent store, but I couldn't be sure. So I removed any calls to <code>saveContext</code> at all so the MOC wouldn't touch the disk, and the blocking call on the main thread is still persisting. </p>
  
  <p>The trace, in text form, looks like this:</p>
  
  <pre><code>Symbol Name
  -[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
   -[NSManagedObjectContext executeFetchRequest:error:]
    -[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]
     _perform
      _dispatch_barrier_sync_f_invoke
       _dispatch_client_callout
        __82-[NSManagedObjectContext(_NestedContextSupport) executeRequest:withContext:error:]_block_invoke_0
         -[NSManagedObjectContext(_NestedContextSupport) _parentObjectsForFetchRequest:inContext:error:]
          -[NSManagedObjectContext executeFetchRequest:error:]
           -[NSPersistentStoreCoordinator executeRequest:withContext:error:]
            -[NSSQLCore executeRequest:withContext:error:]
             -[NSSQLCore objectsForFetchRequest:inContext:]
              -[NSSQLCore newRowsForFetchPlan:]
               -[NSSQLCore _newRowsForFetchPlan:selectedBy:withArgument:]
                -[NSSQLiteConnection execute]
  </code></pre>
  
  <h1>What I Have Tried</h1>
  
  <p>Before we touched the Core Data code, the first thing we did was optimize our JPEGs. We switched to smaller JPEGs and saw a performance boost. Then, we decreased the number of JPEGs we download at a time (from 90 down to 15). This also lead to a significant performance boost. However, we're still seeing 250-350ms-long blocks on the main thread.</p>
  
  <p>The first thing I tried was just getting rid of the background MOC to eliminate the possibility that it might be causing problems. In fact, it made things worse since our update-or-create code was running on the main thread and causing overall animation performance to degrade.</p>
  
  <p>Changing the persistent store to <code>NSInMemoryStoreType</code> had no effect.</p>
  
  <p>Can anyone point me to the "secret sauce" that will give me the UI performance that background managed object contexts have promised?</p>