I'm developing a iPhone app with Core Data. All user data should be synchronized with our servers. For this purpose I created a subclass of NSOperation witch loads new data from our web service and creates corresponding managed objects. To maintain the relationships between them, every object is transmitted with a remoteID (which is the primary key of the relational server DB).
Let's say there are two managed objects: Department <-->> Employee. The synchronization works as follows:
Load all departments from server. For each department: create a Department object and set its remoteID.
Load all employees from server. For each employee: create Employee object, fetch the related Department (by remoteID) and assign it to the employee.
Fetching a department leads to the following exception:
*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0x69c8a10> was mutated while being enumerated.<CFBasicHash 0x69c8a10 [0x2d6d380]>{type = mutable set, count = 1424,
entries => <A list of all newly created entities>
*** Call stack at first throw:
0 CoreFoundation 0x02d04919 __exceptionPreprocess + 185
1 libobjc.A.dylib 0x02e525de objc_exception_throw + 47
2 CoreFoundation 0x02d043d9 __NSFastEnumerationMutationHandler + 377
3 CoreData 0x026225d0 -[NSManagedObjectContext executeFetchRequest:error:] + 4400
4 myApp 0x00059de4 +[AppFactory departmentWithRemoteID:inManagedObjectContext:] + 259
The exception isn't thrown every time. Moving the code to the main thread resolves the problem. I have no idea what's wrong. I created a new NSManagedObjectContaxt in the synchronization thread and passed all managed objects by its NSManagedObjectID.
Any thoughts?
I had the same problem... It was solved because I was using the managedObjectContext that was created on the main thread on a background thread. The solution was to create a different ManagedObjectContext on the background thread, and use the regular persistentStoreCoordinator... it worked fine after that!
The error "someCollection was mutated while being enumerated" is caused by altering a mutable collection i.e. array, dictionary, set etc, while an enumerator is stepping through it. Since you can't enumerate a moving target, this triggers an error.
In this case, the error is most likely caused by trying to enumerate a Department's employees relationship on the main thread e.g. for display in a tableview, while the the background thread is simultaneously adding employees to the relationship.
Did work around this, you have to freeze the UI while you merge the changes from the background thread. For tableviews, a fetched results controller (NSFetchedResultsController) with properly implemented delegate methods in the tableview controller will handle the problem nicely.
The important thing is to send beginUpdates
to the tableview before you merge the new data. This will tell the table that it's underlying data structure is being mutated so it won't try to redraw itself. When the merge is complete, send endUpdates
to the tableview to cause it to display the new information.
Off the top of my head: Is the "synchronization" thread adding new objects to the Department collection while iterating on it on the main thread?
Usually, this type of exception occurs when you're modifying a collection at the same time you're enumerating it. In a multi-threaded scenario, it might also mean your collection is enumerated and updated concurrently without proper thread synchronization.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With