views:

203

answers:

1

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
A: 

Try locking the managed object context before you access it and unlocking it again after you are done with it:

- (void)main
{
    NSInteger songCount = 1;
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
    [moc lock];
    [moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
     [moc unlock];

/* songDict generated here */

    for (id key in songDict)
    {
        [moc lock];
        NSManagedObject *song = [NSEntityDescription insertNewObjectForEntityForName:@"Song" inManagedObjectContext:moc];
        [moc unlock];
        [song setValue:[songDictItem objectForKey:@"Name"] forKey:@"title"];
        [song setValue:[self getArtistObject:(NSString *) [songDictItem objectForKey:@"Artist"]] forKey:@"artist"];

        [songDictItem release];

        songCount++;
    }

    NSError *error;
    [moc lock];
    if (![moc save:&error])
    [NSApp presentError:error];
    [moc unlock];

    [moc lock];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSManagedObjectContextDidSaveNotification object:moc];
    [moc unlock];
    [moc release], moc = nil;
    [[self delegate] importDone];
}

- (NSManagedObject*) getArtistObject:(NSString*)theArtist
{
    NSError *error = nil;
    NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
    [moc lock];
    [moc setPersistentStoreCoordinator:[[self delegate] persistentStoreCoordinator]];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contextDidSave:) name:NSManagedObjectContextDidSaveNotification object:moc];
    [moc unlock];

    NSFetchRequest *fetch = [[[NSFetchRequest alloc] init] autorelease];
    [moc lock];
    NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Artist" inManagedObjectContext:moc];
    [moc unlock];
    [fetch setEntity:entityDescription];

    // object to be returned
    [moc lock];
    NSManagedObject *artistObject = [[NSManagedObject alloc] initWithEntity:entityDescription insertIntoManagedObjectContext:moc];
    [moc unlock];

    // set predicate (artist name)
    NSPredicate *pred = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"name = \"%@\"", theArtist]];
    [fetch setPredicate:pred];

    [moc lock];
    NSArray *response = [moc executeFetchRequest:fetch error:&error];
    [moc unlock];

    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
Michael Fey
No go. It still hits 'return artistObject;' and stops. Interestingly, if I click the button that fires this action several times, it repeats the same action for the first song/artist each time. Is there a way to use the debugger to find out what (if anything) it's waiting for?
spamguy
Not that I'm aware of, but hopefully someone else can jump in.
Michael Fey