Broken Multithreading With Core Data
- by spamguy
This is a better-focused version of an earlier question that touches upon an entirely different subject from before.
I am working on a Cocoa Core Data application with multiple threads. There is a Song and Artist; every Song has an Artist relation. There is a delegate code file not cited here; it more or less looks like the template XCode generates.
I am far better working with the former technology than the latter, and any multithreading capability came from a Core Data template. When I'm doing all my ManagedObjectContext work in one method, I am fine. When I put fetch-or-insert-then-return-object work into a separate method, the application halts (but does not crash) at the new method's return statement, seen below. The new method even gets its own MOC to be safe, and it has not helped any. The result is one addition to Song and a halt after generating an Artist.
I get no errors or exceptions, and I don't know why. I've debugged out the wazoo. My theory is that any errors occurring are in another thread, and the one I'm watching is waiting on something forever.
What did I do wrong with getArtistObject: , and how can I fix it? Thanks.
- (void)main
{
NSInteger songCount = 1;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
/* songDict generated here */
for (id key in songDict)
{
NSManagedObject *song = [NSEntityDescription insertNewObjectForEntityForName:@"Song" inManagedObjectContext:moc];
[song setValue:[songDictItem objectForKey:@"Name"] forKey:@"title"];
[song setValue:[self getArtistObject:(NSString *) [songDictItem objectForKey:@"Artist"]] forKey:@"artist"];
[songDictItem release];
songCount++;
}
NSError *error;
if (![moc save:&error])
[NSApp presentError:error];
[[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:moc];
[moc release], moc = nil;
[[self delegate] importDone];
}
- (NSManagedObject*) getArtistObject:(NSString*)theArtist
{
NSError *error = nil;
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Artist" inManagedObjectContext:moc];
[fetch setEntity:entityDescription];
// object to be returned
NSManagedObject *artistObject = [[NSManagedObject alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:moc];
// set predicate (artist name)
NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"name = \"%@\"", theArtist]];
[fetch setPredicate:pred];
NSArray *response = [moc executeFetchRequest:fetch error:&error];
if (error)
[NSApp presentError:error];
if ([response count] == 0) // empty resultset --> no artists with this name
{
[artistObject setValue:theArtist forKey:@"name"];
NSLog(@"%@ not found. Adding.", theArtist);
return artistObject;
}
else
return [response objectAtIndex:0];
}
@end