I’m using the following code to run a function that parses my xml files…
dispatch_queue_t queue = dispatch_queue_create("updateQueue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue,^ { [self updateFromXMLFile:@"http://path/to/file.xml"]; } );
dispatch_async(queue,^ { [self updateFromXMLFile:@"http://path/to/file1.xml"]; } );
dispatch_async(queue,^ { [self updateFromXMLFile:@"http://path/to/file2.xml"]; } );
dispatch_async(queue,^ { [self updateFromXMLFile:@"http://path/to/file3.xml"]; } );
dispatch_barrier_async(queue,^ {
dispatch_async(dispatch_get_main_queue(),^ {
[self setBottomBarToUpdated];
});
});
Here below is the function updateFromXMLFile:
- (BOOL) updateFromXMLFile:(NSString *)pathToFile {
NSURL *url = [[NSURL alloc] initWithString:pathToFile];
NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url];
XMLParser *parser = [[XMLParser alloc] initXMLParser];
parser.managedObjectContext = self.managedObjectContext;
[xmlParser setDelegate: parser];
BOOL success = [xmlParser parse];
if(success)
return TRUE;
else
return FALSE;
}
The problem I’m coming across is this error message: ***Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0xc675e10> was mutated while being enumerated.'
I’m guessing that it has something to do with all the processes messing with my ManagedObjectContext at the same time. I’m not sure how to handle that though. Any ideas? Thanks!
You need to show the code for how your XMLParser handles its delegate responsibilities, because that’s what’s being called.
Now, you are parsing multiple files at the same time, from within separate threads. They are all calling into different XMLParser objects, but each of those is using the same managed object context (MOC).
If you are using the default MOC setup, you need to reconvene all those MOC calls to the main thread (if that is, indeed where you first created your context). If you use confinement, and your MOC is not created on the main thread, then you are giving yourself more trouble.
However, it’s a pretty simple fix. In that parser delegate method, whenever you use the managed object context, enclose it in a call to dispatch that part on the main thread.
Now, for doing bulk downloads into Core Data, you are probably better off using one of two approaches.
Create a new MOC, attached directly to the persistent store coordinator, and do all your saving there. Your main MOC needs to observe Save notifications and merge those changes.
Or, make the new MOC be a child of your main MOC, and save directly into it, then it can save.
If, however, your managed object context is of either NSMainQueueConcurrencyType or NSPrivateQueueConcurrency type (only way to do second option above), then you can just use its perfromBlock method…
The bottom line is that a MOC can be created with one of three concurrency types. If it is NSConfinementConcurrencyType, then you must not touch it outside the thread in which it was created. If it is NSMainQueueConcurrencyType, you have to use performBlock* or only touch it in the main thread. If it is NSPrivateConcurrencyType, you must use performBlock*.