Note that there are some explanatory texts on larger screens.

plurals
  1. PO"Collection was mutated while being enumerated" on executeFetchRequest
    primarykey
    data
    text
    <p>I'm stuck on a problem for hours now and having read everything about this on stackoverflow (and apply every advices found), I'm now officially in need for help. ;o)</p> <p>Here is the context :</p> <p>In my iPhone project, I need to import data on the background and insert it in a managed object context. Following the advices found here, here is what I'm doing :</p> <ul> <li>Save the main moc</li> <li>Instantiate a background moc with the persistent store coordinator used by the main moc</li> <li>Register my controller as an observer of the NSManagedObjectContextDidSaveNotification notification for the background moc</li> <li>Call the import method on a background thread</li> <li>Each time data is received, insert it on the background moc</li> <li>Once all the data has been imported, save the background moc</li> <li>Merge the changes into the main moc, on the main thread</li> <li>Unregister my controller as an observer for the notification</li> <li>Reset and release the background moc</li> </ul> <p>Sometimes (and randomly), the exception...</p> <pre><code>*** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection &lt;__NSCFSet: 0x5e0b930&gt; was mutated while being enumerated... </code></pre> <p>...is thrown when I call executeFetchRequest on the background moc, to check if the imported data already exists in the database. I wonder what is mutating the set since there is nothing that run outside the import method.</p> <p>I've included the entire code of my controller and my test entity (my project consisting of these two classes and the app delegate, which has been unmodified) :</p> <pre><code>// // RootViewController.h // FK1 // // Created by Eric on 09/08/10. // Copyright (c) 2010 __MyCompanyName__. All rights reserved. // #import &lt;CoreData/CoreData.h&gt; @interface RootViewController : UITableViewController &lt;NSFetchedResultsControllerDelegate&gt; { NSManagedObjectContext *managedObjectContext; NSManagedObjectContext *backgroundMOC; } @property (nonatomic, retain) NSManagedObjectContext *managedObjectContext; @property (nonatomic, retain) NSManagedObjectContext *backgroundMOC; @end // // RootViewController.m // FK1 // // Created by Eric on 09/08/10. // Copyright (c) 2010 __MyCompanyName__. All rights reserved. // #import "RootViewController.h" #import "FK1Message.h" @implementation RootViewController @synthesize managedObjectContext; @synthesize backgroundMOC; - (void)viewDidLoad { [super viewDidLoad]; self.navigationController.toolbarHidden = NO; UIBarButtonItem *refreshButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemRefresh target:self action:@selector(refreshAction:)]; self.toolbarItems = [NSArray arrayWithObject:refreshButton]; } #pragma mark - #pragma mark ACTIONS - (void)refreshAction:(id)sender { // If there already is an import running, we do nothing if (self.backgroundMOC != nil) { return; } // We save the main moc NSError *error = nil; if (![self.managedObjectContext save:&amp;error]) { NSLog(@"error = %@", error); abort(); } // We instantiate the background moc self.backgroundMOC = [[[NSManagedObjectContext alloc] init] autorelease]; [self.backgroundMOC setPersistentStoreCoordinator:[self.managedObjectContext persistentStoreCoordinator]]; // We call the fetch method in the background thread [self performSelectorInBackground:@selector(_importData) withObject:nil]; } - (void)_importData { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundMOCDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.backgroundMOC]; FK1Message *message = nil; NSFetchRequest *fetchRequest = nil; NSEntityDescription *entity = [NSEntityDescription entityForName:@"FK1Message" inManagedObjectContext:self.backgroundMOC]; NSPredicate *predicate = nil; NSArray *results = nil; // fake import to keep this sample simple for (NSInteger index = 0; index &lt; 20; index++) { predicate = [NSPredicate predicateWithFormat:@"msgId == %@", [NSString stringWithFormat:@"%d", index]]; fetchRequest = [[[NSFetchRequest alloc] init] autorelease]; [fetchRequest setEntity:entity]; [fetchRequest setPredicate:predicate]; // The following line sometimes randomly throw the exception : // *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection &lt;__NSCFSet: 0x5b71a00&gt; was mutated while being enumerated. results = [self.backgroundMOC executeFetchRequest:fetchRequest error:NULL]; // If the message already exist, we retrieve it from the database // If it doesn't, we insert a new message in the database if ([results count] &gt; 0) { message = [results objectAtIndex:0]; } else { message = [NSEntityDescription insertNewObjectForEntityForName:@"FK1Message" inManagedObjectContext:self.backgroundMOC]; message.msgId = [NSString stringWithFormat:@"%d", index]; } // We update the message message.updateDate = [NSDate date]; } // We save the background moc which trigger the backgroundMOCDidSave: method [self.backgroundMOC save:NULL]; [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.backgroundMOC]; [self.backgroundMOC reset]; self.backgroundMOC = nil; [pool drain]; } - (void)backgroundMOCDidSave:(NSNotification*)notification { if (![NSThread isMainThread]) { [self performSelectorOnMainThread:@selector(backgroundMOCDidSave:) withObject:notification waitUntilDone:YES]; return; } // We merge the background moc changes in the main moc [self.managedObjectContext mergeChangesFromContextDidSaveNotification:notification]; } @end // // FK1Message.h // FK1 // // Created by Eric on 09/08/10. // Copyright 2010 __MyCompanyName__. All rights reserved. // #import &lt;CoreData/CoreData.h&gt; @interface FK1Message : NSManagedObject { } @property (nonatomic, retain) NSString * msgId; @property (nonatomic, retain) NSDate * updateDate; @end // // FK1Message.m // FK1 // // Created by Eric on 09/08/10. // Copyright 2010 __MyCompanyName__. All rights reserved. // #import "FK1Message.h" @implementation FK1Message #pragma mark - #pragma mark PROPERTIES @dynamic msgId; @dynamic updateDate; @end </code></pre> <p>This is all ! The whole project is here. No table view, no NSFetchedResultsController, nothing else than a background thread that import data on a background moc.</p> <p>What could mutate the set in this case ?</p> <p>I'm pretty sure I'm missing something obvious and it's driving me mad.</p> <p>EDIT: </p> <p>Here is the full stack trace :</p> <pre><code> 2010-08-10 10:29:11.258 FK1[51419:1b6b] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection &lt;__NSCFSet: 0x5d075b0&gt; was mutated while being enumerated.&lt;CFBasicHash 0x5d075b0 [0x25c6380]&gt;{type = mutable set, count = 0, entries =&gt; } ' *** Call stack at first throw: ( 0 CoreFoundation 0x0255d919 __exceptionPreprocess + 185 1 libobjc.A.dylib 0x026ab5de objc_exception_throw + 47 2 CoreFoundation 0x0255d3d9 __NSFastEnumerationMutationHandler + 377 3 CoreData 0x02287702 -[NSManagedObjectContext executeFetchRequest:error:] + 4706 4 FK1 0x00002b1b -[RootViewController _fetchData] + 593 5 Foundation 0x01d662a8 -[NSThread main] + 81 6 Foundation 0x01d66234 __NSThread__main__ + 1387 7 libSystem.B.dylib 0x9587681d _pthread_start + 345 8 libSystem.B.dylib 0x958766a2 thread_start + 34 ) terminate called after throwing an instance of 'NSException' </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload