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:
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?
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. OnceNSNotificationCenterdetects 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
Thanks! I think this is a bug in their library
Welcome
I’ve submitted the bug to the author.
Thank you so much. I’ve been using MagicalRecord and have been looking for a way to do this for 2 weeks now
Glad to help. Hope you solved the problem
I’ve been looking for this for ages…