title: gcd/dispatch_async and CoreData freezes app
body: <p>For some reason using dispatch_async and Core Data together causes my app to completely freeze, but not crashed. </p>
  
  <h2>Symptom</h2>
  
  <p>The user interface is not responsive. The app does not crash. </p>
  
  <p>The app uses <code>[[UIAccelermeter sharedAccelerometer] setDelegate: self]</code> to get accelerometer values continuously. The "<code>accelerometer:didAccelerate:</code>" callback runs on main thread. When this issue occurs, the callback no longer executes.</p>
  
  <p>Therefore the main thread appears to be "frozen".</p>
  
  <h2>Context</h2>
  
  <p>I use <code>NSURLConnection</code> in my app to send HTTP requests to my server. In connectionDidFinishLoading, where response data is handled, it takes about 2 seconds to execute and the user interface would be unresponsive during those 2 seconds, because it runs in the main thread.</p>
  
  <p>After some research, it seems that <code>gcd/dispatch_async</code> is the best solution for this situation to execute the data handling in the background. So, in <code>connectionDidFinishLoading</code>, I added the following gcd calls:</p>
  
  <pre><code>dispatch_queue_t queue;
  queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
  dispatch_async(queue, ^{
      [self handleTheData: connection];
  });
  </code></pre>
  
  <p>This works fine sometimes, but it would cause app to freeze randomly - Even though same code is used, with the same data in Core Data storage, repeated tests show that symptom can be observed X% of the time. The chance of issue happening is affected by a few factors, explained further below.</p>
  
  <h2>What does handleTheData() do?</h2>
  
  <p>It examines the response data from <code>NSURLConnection</code>, which is JSON formatted string. The string is 3 lists of entity, and each entity is an array of array of numbers. So there are codes to convert the JSON formatted string into 3 NSMutableArray of custom object, where each object is a subclassed NSManagedObject.</p>
  
  <p>During the convertion, since these ojects are "temporary" in that they may or may not get stored permanently, they are created in "nil" NSManagedObjectContext, like so:</p>
  
  <pre><code>SampleEntity *newEntity= 
  (SampleEntity *) [[NSManagedObject alloc] initWithEntity:entity 
                         insertIntoManagedObjectContext:nil
                 ];
  </code></pre>
  
  <p>This way, they will not be mixed with the main context.</p>
  
  <p>Then these new objects are compared with existing entities in data store. So there are some codes to fetch from data store repeatedly to see if a particular new entity already existed, and depending on the data of the new entity, the new entity may be saved to data store, or the existing entity may be updated.</p>
  
  <p>[managedObjectContext save: &amp;error] is called often to ensure that changes are saved permanently.</p>
  
  <h2>Anything else running in background?</h2>
  
  <p>As mentioned in Symptom section, Accelerometer runs in the background in the main thread using [[UIAccelermeter sharedAccelerometer] setDelegate: self] </p>
  
  <p>AudioUnits have also been set up to run in the background (on a separate "priority" thread according to Apple docs) to produce sound.</p>
  
  <h2>Findings on cause of issue</h2>
  
  <p>It was found that the chance of issue happening is affected by the following factors:</p>
  
  <ul>
  <li>If some debugging code is commented out, such as NSLog(@"fetchedResult: %@", fetchedResult), the chance of issue happening decreases (but it still occurs).</li>
  <li>If accelerometer is not used, the issue almost never occur (but not 100% sure as I did a limited number of tests).</li>
  <li>If accelerometer is used, the chance of issue happening is about 50/50.</li>
  <li>If some of the Core Data codes such as [sampleEntity setXYZ..] is commented out, the issue almost never occurs even though accelerometer is used.</li>
  </ul>
  
  <h2>Second Issue</h2>
  
  <p>Also, even if the main thread is not frozen, ANOTHER ISSUE occurs. The data handling code would end half way through without throwing errors.</p>
  
  <ul>
  <li>What that means is, data handling will only be partially done and there is no error thrown, and the main thread continues to run fine.</li>
  <li>This second issue occurs frequently (but not always) whenever the main issue does not occur.</li>
  </ul>
  
  <p>Interesting problem isn't it? :)</p>
  
  <p><em>Edit</em></p>
  
  <ul>
  <li>3/1/2013 - I previously thought that the cause of issue was iOS 6. Sorry, that was completely wrong. Modified description to reflect new findings.</li>
  </ul>