问题
I'm using an NSXMLParser to process a large and complex XML file that needs to end up in my Core Data model. To do this I am following the design pattern as discussed in the iOS book by Conway and Hillegass, where the delegate of the NSXMLParser is changed every time a new node is reached and new nodes are created on the fly. To create the entities, I am using MagicalRecord's MR_createEntity
for each new node during the parsing to set up my data model. After the parsing is finished I call
[[NSManagedObjectContext MR_defaultContext] MR_saveToPersistentStoreAndWait];
to save the new entities to my Core Data store.
This all works fine, until I recently decided to move the parsing into a background thread. And I noticed the XML data was not always imported. So after some Googling I found that MR_createEntity
should not be used on a background thread (link: https://github.com/magicalpanda/MagicalRecord/issues/298).
So what to do? I see two possible solutions:
During the parsing, just create a Foundation based structure of all the nodes, a mixture of NSDictionaries and NSArrays. This can be done on a background thread. Once done, I go back to the main thread and save my data into Core Data using
MR_importValuesForKeysWithObject
or something similar (as described here: http://www.cimgf.com/2012/05/29/importing-data-made-easy/). But will that work with combinations of deeply nested dictionaries and arrays?During the parsing, instead of calling
MR_CreateEntity
, I use[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) { MyEntity *entity = [MyEntity MR_createInContext:localContext]; }];
every time I come upon a new node as suggested in the github link above.
So before I start cutting up and modifying my code, what would be the way to go? Maybe there is another approach?
回答1:
If I understand the MagicalRecord source code correctly, you need only a single
saveInBackgroundWithBlock:completion:
call:
[MagicalRecord saveInBackgroundWithBlock:^(NSManagedObjectContext *localContext) {
// ... parse XML ...
// ... create entities with:
MyEntity *entity = [MyEntity MR_createInContext:localContext];
// ...
} completion:^{
NSLog("Import finished");
}];
This
- creates a temporary background context,
- executes the first block on the background queue associated with that context,
- calls
MR_saveToPersistentStoreAndWait
to save the temporary context to the main context and save the main context to the persistent core, - and finally executes the completion block.
回答2:
Do you try this? https://stackoverflow.com/a/13924299/1979953
like this.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// dispatch_async mean your NSXMLParser in a backgound thread
MyEntity *entity = [MyEntity MR_createEntity];
...
[[NSManagedObjectContext MR_contextForCurrentThread] saveNestedContexts];
});
but, you found that MR_createEntity should not be used on a background thread. So I'm confused.
来源:https://stackoverflow.com/questions/18543739/using-magicalrecord-and-nsxmlparser-in-a-background-thread