views:

95

answers:

2

Has anyone run into this before?

When I choose to delete a row from my tableView (populated by an FRC), the app doesn't crash or hang. It doesn't do anything. The delete button stays selected and if I click elsewhere on the simulator, the delete button deselects and disappears, but the cell is never removed form the UI. I'm sure there is a dumb oversight I am making here, but I can't spot it. Below are the relevant portions of my code.

I have my UITableViewController interface declared as such:

#import <UIKit/UIKit.h>
#import "RubricAppDelegate.h"


@interface ClassList : UITableViewController <NSFetchedResultsControllerDelegate> {
    NSMutableArray *classList;
    NSFetchedResultsController *fetchedResultsController;
    NSManagedObjectContext *managedObjectContext;

}

@property(nonatomic,retain) NSMutableArray *classList;
@property(nonatomic, retain) NSFetchedResultsController *fetchedResultsController;
@property(nonatomic, retain) NSManagedObjectContext *managedObjectContext;

- (IBAction) grade:(id)sender;

@end

In its implementation file, I have:

- (void)viewDidLoad {

    [super viewDidLoad];

    RubricAppDelegate *appDelegate = (RubricAppDelegate *)[[UIApplication sharedApplication] delegate];
    managedObjectContext = [appDelegate managedObjectContext];

    NSEntityDescription *entity = [NSEntityDescription entityForName:@"myClass" inManagedObjectContext:managedObjectContext];
    NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease];
    [request setEntity:entity];

    NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"classID" ascending:YES];
    NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
    [request setSortDescriptors:sortDescriptors];
    [sortDescriptor release];


    fetchedResultsController = [[NSFetchedResultsController alloc]
                                           initWithFetchRequest:request 
                                           managedObjectContext:self.managedObjectContext
                                           sectionNameKeyPath:nil cacheName:nil];
    NSError *error;
    [fetchedResultsController performFetch:&error];
}

And

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        myClass *result = (myClass *)[fetchedResultsController objectAtIndexPath:indexPath];
        [managedObjectContext deleteObject:result]; 
            NSError *error;
            [managedObjectContext save:&error]; 
    }   
    else if (editingStyle == UITableViewCellEditingStyleInsert) {
        //Not yet implemented   
    }   
}

And

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
       atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {

    UITableView *tableView = self.tableView;

    switch(type) {

        case NSFetchedResultsChangeInsert:

            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
                             withRowAnimation:UITableViewRowAnimationFade];

            break;

        case NSFetchedResultsChangeDelete:

            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                                 withRowAnimation:UITableViewRowAnimationFade];

            break;

        case NSFetchedResultsChangeUpdate:

            [self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];

            break;

        case NSFetchedResultsChangeMove:

            [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
                             withRowAnimation:UITableViewRowAnimationFade];

            [tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] 
                             withRowAnimation:UITableViewRowAnimationFade];

            break;
    }

}

Also

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.row == [[fetchedResultsController fetchedObjects] count]) {
        return UITableViewCellEditingStyleInsert;
    }
    return UITableViewCellEditingStyleDelete;
}

That above code makes the cell just beyond my fetch-populated cells an insert cell, but the rest delete cells.

I have my UITableView connected to my File's Owner for its delegate and datasource in IB. What do I need to change to get NSFetchedResultsChangeDelete: to trigger?

UPDATE:

I have added [managedObjectContext save:&error]; to commitEditingStyle and verified via breakpoint that it is being hit when I choose to delete a cell. I know the save is processing correctly, because if I quit and re-run the app, the cells that I chose to delete are in fact deleted.

However, when I press the delete button, there is still nothing happening. The button stays selected until I click elsewhere, thereby deselecting it.

+1  A: 

It looks like you need to implement editingStyleForRowAtIndexPath to actually declare the cells your trying to delete as deletable.

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {
  return UITableViewCellEditingStyleDelete;
}

Also, it doesn't appear that your saving your managedObjectContext.

EDIT: So it sounds like your model is commiting, but your tableview is reloading.

Try implementing

- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
  [self.tableView beginUpdates];
}

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
  [self.tableView endUpdates];
}
DVG
Sorry, I should have included that in my original post. I have updated it with that code. Thanks for spotting that, but the problem must be elsewhere.
Spindler
But I think you might be onto something with saving the moc...sorry I glanced over that the first time I read your post. I'm testing that right now and dealing with an error it brought up, but I'll let you know if I really hit another wall.
Spindler
If you delete with no apparent change, kill the app then build and run again, is the row still there?
DVG
The good news is that the row is being deleted from the data structure. It isn't there when I build and run again. The issue I am having is getting the animation to trigger in -NSFetchedResultsChangeDelete:
Spindler
Answer updated.
DVG
Thanks for your help DVG. The missing piece was setting the delegate for the NSFetchedResultsController.
Spindler
+1  A: 

Can you show the code that builds the NSFetchedResultsController? Now that you have the save in your code as @DVG suggested then you should be getting callbacks. Perhaps your delegate is not being set properly.

Update

As I suspected you are not setting the delegate on the NSFetchedResultsController:

[fetchedResultsController setDelegate:self];

You should start receiving updates after adding that line around where you call -performFetch:.

Marcus S. Zarra
I have included the initialization of my NSFetchedResultsController in my implementation file code above (2nd code block). My RubricAppDelegate is set up identically to the Apple docs, but let me know if you want to see that anyways.
Spindler
Answer updated.
Marcus S. Zarra