Deleting a cell in search bar table view causes delete to be executed twice

淺唱寂寞╮ 提交于 2020-01-06 08:32:14

问题


I have a table view backed up by core data with NSFetchedResultsController instance. This table has a search bar that displays filtered data. The search bar has a separate NSFetchedResultsController (FRC from now) instance.

So far so good, the data is fetched and shown as expected in the table view and also shown correctly in the search bar's table view (when searching for data).

My problem is that if I try to delete a cell in the search bar's table view then I get a coredata exception :

error: Serious application error. An exception was caught from the delegate of NSFetchedResultsController during a call to -controllerDidChangeContent:. attempt to delete row 0 from section 0 which only contains 0 rows before the update with userInfo (null)

Further examination shows that the FRC's controllerWillChangeContent method is called twice on one cell deletion!. This causes deleteRowsAtIndexPaths to be called twice for the same cell (thus the coredata exception).

Playing with it some more I have found out that this problem happens from the first time the search bar's table view is shown after a search. (Even when I go back and delete the cell in the regular table view the problem occurs)

I've made sure that the deleteRowsAtIndexPaths method is called only once in the code (in the FRC's didChangeObject delegate method).

Now I am not sure which code to show so I won't just spill it all. let me know which one you need to look at if you have an idea on what the problem is.

This is the code where the table is instructed to delete a row :

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

    DLog(@"didChangeObject type %lu with object %@", (unsigned long)type, anObject);
    switch(type) {
        case NSFetchedResultsChangeInsert:
            [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeDelete:
            [self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;

        case NSFetchedResultsChangeUpdate:
            [self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath forTable:self.tableView];
            break;

        case NSFetchedResultsChangeMove:
            [self.tableView deleteRowsAtIndexPaths:[NSArray
                                               arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            [self.tableView insertRowsAtIndexPaths:[NSArray
                                               arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
            break;
    }
}

This method is called when I save the context after I delete the object for the selected cell.

The method where I save the context:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        [_managedObjectContext deleteObject:[_notesFetcher objectAtIndexPath:indexPath]];
        NSError *error;
        if (![_managedObjectContext save:&error]) {
            DLog(@"Failed deleting object : %@", [error localizedDescription]);
        }
    }   
}

And for some reason this method is called once but invokes didChangeObject twice with the same change type (2-Delete) for the same cell.

UPDATE

When I log for the stack trace in the method didChangeObject I get this:

[UITableView animateDeletionOfRowWithCell:] + 107 12 UIKit
0x01316a35 -[UITableViewCell _swipeDeleteButtonPushed] + 70 13 libobjc.A.dylib 0x02346874 -[NSObject performSelector:withObject:withObject:] + 77 14 UIKit
0x010a8c8c -[UIApplication sendAction:to:from:forEvent:] + 108 15 UIKit 0x010a8c18 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61 16 UIKit
0x011a06d9 -[UIControl sendAction:to:forEvent:] + 66 17 UIKit
0x011a0a9c -[UIControl _sendActionsForEvents:withEvent:] + 577 18 UIKit 0x0119fd4b -[UIControl touchesEnded:withEvent:] + 641 19 UIKit
0x0141ad7f _UIGestureRecognizerUpdate + 7166 20 UIKit
0x010e5d4a -[UIWindow _sendGesturesForEvent:] + 1291 21 UIKit
0x010e6c6a -[UIWindow sendEvent:] + 1030 22 UIKit
0x010baa36 -[UIApplication sendEvent:] + 242 23 UIKit
0x010a4d9f _UIApplicationHandleEventQueue + 11421

As you can see the table's swipeDeleteButtonPushed method is called twice on one delete operation as I described above. How can this be triggered twice when I only pushed the delete button once ? any ideas ?


回答1:


You need to always check which controller is calling your delegate method and act accordingly. Similarly you need to check which tableView is calling your delegate method. Assuming that your viewController is the delegate for both the search fetchedresultscontroller and the normal fetchedresultscontroller as well as the search tableView and the normal tableView.

So you need something,like

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

    If (tableView == searchTableView) {
      // do stuff to searchTableView

    } else  {
      // do stuff to normalTableView

    }
}

Or in the fetchedResultsController delegate methods (and I am pretty sure this will be where you are getting two calls acting on the same tableView) something like

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

    If (controller == searchFetchedResultsController) {
       // do stuff to searchTableview

    } else {
       // do stuff to normaltableview

    }
}


来源:https://stackoverflow.com/questions/20790234/deleting-a-cell-in-search-bar-table-view-causes-delete-to-be-executed-twice

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!