I like the smell of Swift in the morning…

“Collection was mutated while being enumerated” during CoreData operation on background thread

Posted: | Author: | Filed under: iOS, Objective-C | Tags: , , | 7 Comments »

During my current project I had to move a time consuming CoreData operation to a background thread to avoid a frozen UI. After reading some horror stories about using CoreData on a background thread I was actually surprised how straight forward it was. I used Apple’s sample code ThreadedCoreData as a guidance. When I tested my changes everything went smooth. Until I started to touch my app’s UI while the background process was running. Suddenly the app crashed and the following exception was thrown:

*** Terminating app due to uncaught exception 'NSGenericException',
reason: '*** Collection <__NSCFSet: 0x1f0ec200> was mutated while
being enumerated.'

The exception was being thrown on the background thread during a call to

[NSManagedObjectContext executeFetchRequest:error:]

What happened?

In Apple’s example code the CoreData operations happen inside the main method of a custom subclass of NSOperation. That subclass is initialized using a custom initWithData: method and then added to a NSOperationQueue.

When doing CoreData operations on a background thread it is important that the background thread uses it’s own instance of NSManagedObjectContext. And this NSManagedObjectContext has to be instantiated on the background thread.

And that was the problem.

In Apple’s example the NSManagedObjectContext for the background thread is instantiated in the custom initWithData: method of the custom ParseOperation class. But that method is called on the main thread when instantiating a new ParseOperation object before adding it to the NSOperationQueue. So the NSManagedObjectContext instance is created on the main thread!

The solution was quite simple:

After moving the code that instantiates the NSManagedObjectContext from the initWithData: method (called from the main thread) to the main method (called from the background thread), the problem vanished and the code run smoothly.

So, when using CoreData in a background thread make sure that the background thread has it’s own NSManagedObjectContext instance that was created on the background thread!

CoreData error: “The model used to open the store is incompatible with the one used to create the store”

Posted: | Author: | Filed under: iOS, Xcode | Tags: | 4 Comments »

When I started to play around with CoreData for the first time, I came across a strange error. The error description said “The model used to open the store is incompatible with the one used to create the store”. At first I just couldn’t figure out what the problem was. As soon as I tried to access the NSManagedObjectContext the app crashed.

The solution is really simple: Whenever you change something your CoreData data model, you have to delete the old compiled app from the simulator or device. CoreData uses SQLite3 which is nothing more than a file in your app’s filesystem. If you do not delete the old version of your app the file remains in the file system and does not reflect the changes that you made in the data model. The SQLite file will only be deleted when you delete the whole app.

So the golden rule is: Whenever you change something in the data model of your CoreData driven App, make sure to delete the old version of the app before compiling and running the new one.