Gaby Fitcal Gaby Fitcal - 4 months ago 165
iOS Question

Core Data was mutated while being enumerated

I've an annoying problem with

Core Data
. My app need to get contacts from iPhone and save it in my database. I'm trying to do that in background thread.

I use above code for that:

[self performSelectorInBackground:@selector(fetchingContact) withObject:nil];


-(void)fetchingContact{
// Some Code
for (int i = 0; i < nPeople; i++)
{
//Some Code
NSManagedObjectContext *context = [APP_DELEGATE managedObjectContext];
ABRecordID recordID = ABRecordGetRecordID(person);
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contact" inManagedObjectContext:context];
[fetchRequest setEntity:entity];
NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"(contactId = '%d')",recordID]];
[fetchRequest setPredicate:predicate];
NSError *error = nil;
//crash
NSArray *contactObjArray = [context executeFetchRequest:fetchRequest error:&error];
//crash
if (error) {}
Contact *contacts;
if (contactObjArray.count == 0) {
contacts = [NSEntityDescription insertNewObjectForEntityForName:@"Contact" inManagedObjectContext:context];
}else {
contacts = [contactObjArray objectAtIndex:0];
}
//Some Code
}
}


In AppDelegate:

- (NSManagedObjectContext *)managedObjectContext
{
NSLog(@"managedObjectContext");
// Returns ;the managed object context for the application (which is already bound to the persistent store coordinator for the application.)
if (_managedObjectContext != nil) {
return _managedObjectContext;
}

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (!coordinator) {
return nil;
}
_managedObjectContext = [[NSManagedObjectContext alloc]initWithConcurrencyType: NSMainQueueConcurrencyType];
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
return _managedObjectContext;
}


Here I try to save in my
Core Data
but it crash with error :


* Terminating app due to uncaught exception 'NSGenericException', reason: '* Collection <__NSCFSet: 0x15fad880> was mutated while being enumerated.'` at this line:


NSArray *contactObjArray = [context executeFetchRequest:fetchRequest error:&error];


I search already online, I found a lot of things but nothing helps me. When I run that, there is no place where
Core Data
is changed, or Contact entity. That does this error very strange.

If I run it in main thread I get no errors/ no crash, but if the app is quit in that time(while is executed) I lose all content from
Contact


Please, any help. Tell me if needs more informations.

Answer

This error happen when you are modifying core data while you try to get them.

That also could be cause of the loop you're doing, you are inserting a new object in coredata without saving before you do an other retrieve. Try saving your managedobjectcontext :

favorite I have an annoying problem with Core Data. My app need to get contacts from iPhone and save it in my database. I'am trying to do that in background thread.

I use above code for that:

[self performSelectorInBackground:@selector(fetchingContact) withObject:nil];


-(void)fetchingContact{
// Some Code
for (int i = 0; i < nPeople; i++)
{
//Some Code
    NSManagedObjectContext *context = [APP_DELEGATE managedObjectContext];
    ABRecordID recordID = ABRecordGetRecordID(person);
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"Contact" inManagedObjectContext:context];
    [fetchRequest setEntity:entity];
    NSPredicate *predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"(contactId = '%d')",recordID]];
    [fetchRequest setPredicate:predicate];
    NSError *error = nil;
    NSArray *contactObjArray = [context executeFetchRequest:fetchRequest error:&error];
    if (error) {}
    Contact *contacts;
    if (contactObjArray.count == 0) {
        contacts = [NSEntityDescription insertNewObjectForEntityForName:@"Contact" inManagedObjectContext:context];
        [context save:&error];
    }else {
        contacts = [contactObjArray objectAtIndex:0];
    }
//Some Code
}
}

If that doesn't solve your problem, maybe check if your method is called multiple times.