Core Data: Perform Operations In Background Threads With MagicalRecord

After spending two whole days working with Core Data, I finally found the best way (at least for me) of performing operations in background threads. Apple claimed in its documentation that “saving in a background thread is error-prone”. This is really not an exaggeration, it seems.

Through research, there seemed to be a lot of methods to implement operations in background threads, including NSNotificationCenter method, parent context method, and so many other variants. However, they either don’t work for me, or do not meet my specific needs.

Finally, I found a great wrapper class called MagicalRecord. The documentation says that performing core data operations is just as easy as this:

(Note that to use this code, you must first add MagicalRecord to your project.)

Person *person = ...;
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
    Person *localPerson = [person MR_inContext:localContext];
    localPerson.firstName = @"John";
    localPerson.lastName = @"Appleseed";
}];

I thought that was the end of the headache. I was wrong.

MagicalRecord #222 works extremely well for the most part; however, it fails to save the data to local file after performing background operations. This seems to be a bug, as it should have worked fine, as claimed by the documentation.

After more searching, I finally found the solution that, once and for all, puts an end to this nightmare.

Person *person = ...;
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext){
    Person *localPerson = [person MR_inContext:localContext];
    localPerson.firstName = @"John";
    localPerson.lastName = @"Appleseed";
} completion:^{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        [[NSManagedObjectContext defaultContext] save];
    }];
}];

The added code actually tells the main NSManagedObjectContext to forcefully save the data on main context after performing the operations, thus archiving our goal.

Note that by the time of this writing, such bug has not been resolved. You might find this bug already fixed when you later download the MagicalRecord.



If you enjoyed the article, please share with your friends:

    • Kevin
    • September 25th, 2012 12:31am

    Thank you for the solution. However, since the context is now saved on the main thread, a large save operation is still quite slow. Are there no better solutions?

      • Ted
      • September 25th, 2012 11:09am

      Indeed, large save operation can still be slow and blocking the main thread.
      One possible workaround is to setup an NSNotificationCenter, so that the save operation is performed in the background. Once NSNotificationCenter detects that a change has been made to the specific context, it will call a designated selector, so that you can merge changes performed in a background thread to a main thread. There will be significantly less operation on the main thread.

      Here is an example of this implementation : http://stackoverflow.com/questions/7540801/core-data-and-threads-grand-central-dispatch

    • Joris
    • September 18th, 2012 6:19pm

    Thanks! I think this is a bug in their library

      • Ted
      • September 18th, 2012 6:34pm

      Welcome :)
      I’ve submitted the bug to the author.

    • Mav
    • September 14th, 2012 2:12am

    Thank you so much. I’ve been using MagicalRecord and have been looking for a way to do this for 2 weeks now

      • Ted
      • September 14th, 2012 8:17am

      Glad to help. Hope you solved the problem :)

    • Mary
    • September 13th, 2012 9:52pm

    I’ve been looking for this for ages…

  1. No trackbacks yet.