NSFetchedResultsChangeDelete not being triggered

2019-05-11 13:49发布

问题:

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:

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



回答2:

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];
}