删除搜索栏表视图中的单元格会导致删除执行两次

时间:2013-12-26 19:34:52

标签: core-data ios7 tableview searchbar

我有一个由NSFetchedResultsController实例的核心数据备份的表视图。 此表有一个显示已过滤数据的搜索栏。搜索栏有一个单独的NSFetchedResultsController(从现在起为FRC)实例。

到目前为止,数据已在表格视图中按预期显示并在搜索栏的表格视图中正确显示(搜索数据时)。

我的问题是,如果我尝试删除搜索栏的表格视图中的单元格,那么我会收到coredata例外:

  

错误:严重的应用程序错误。从中捕获了一个例外   调用期间NSFetchedResultsController的委托   -controllerDidChangeContent :.尝试在使用userInfo(null)

更新之前从第0部分删除第0行,该第0行仅包含0行

进一步检查表明FRC的controllerWillChangeContent方法在一次细胞删除时被调用两次!这会导致deleteRowsAtIndexPaths为同一个单元格调用两次(因此是coredata异常)。

再次使用它我发现这个问题是在搜索后第一次显示搜索栏的表格视图时发生的。 (即使我回去并删除常规表视图中的单元格,也会出现问题)

我确保deleteRowsAtIndexPaths方法只在代码中调用一次(在FRC的didChangeObject委托方法中)。

现在我不确定要显示哪个代码,所以我不会只是泄漏所有代码。如果你对问题是什么有所了解,请告诉我你需要看哪一个。

这是指示表删除行的代码:

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

在删除所选单元格的对象后保存上下文时调用此方法。

我保存上下文的方法:

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

由于某种原因,此方法被调用一次,但对同一个单元格使用相同的更改类型(2-Delete)调用didChangeObject两次。

更新

当我在方法didChangeObject中记录堆栈跟踪时,我得到了这个:

  

[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

正如您所看到的,如上所述,在一次删除操作中,表的swipeDeleteButtonPushed方法被调用两次。当我只按一次删除按钮时,如何触发两次?任何想法?

1 个答案:

答案 0 :(得分:1)

您需要始终检查哪个控制器正在调用您的委托方法并采取相应措施。同样,您需要检查哪个tableView正在调用您的委托方法。假设您的viewController搜索 delegate正常 fetchedresultscontroller的{​​{1}}以及搜索 fetchedresultscontroller正常 tableView

所以你需要一些东西,比如

tableView

或者- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { If (tableView == searchTableView) { // do stuff to searchTableView } else { // do stuff to normalTableView } } 委托方法( ,我很确定这将是你在同一个tableView 上进行两次调用的地方)

fetchedResultsController