tableView:在删除项目后使用nil indexPath调用cellForRowAtIndexPath

时间:2011-08-04 12:27:54

标签: ios null nsindexpath uitableview

我有一个由UITableView管理的香草NSFetchedResultsController来显示给定核心数据实体的所有实例。

当用户通过向其移动来删除表格视图中的条目时,tableView:cellForRowAtIndexPath:最终会在UITableViewControllernil indexPath被调用。由于我没想到会使用nil indexPath来调用它,因此应用程序崩溃了。

我可以通过检查nil值然后返回一个空单元来解决崩溃问题。这似乎有效,但我仍然担心我可能处理了一些错误。有任何想法吗?有没有人见过使用tableView:cellForRowAtIndexPath: nil来调用indexPath

请注意,只有当用户通过滑动单元格从表格视图中删除时才会发生这种情况。使用表格视图编辑模式删除项目时,不会发生这种情况。删除单元格的两种方法有什么不同?

在表格视图委托方法中获取nil indexPath是否真的可以?

我的视图控制器代码非常标准。这是删除:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source
        NSManagedObject *managedObject = [self.fetchedResultsController objectAtIndexPath:indexPath];
        [self.moc deleteObject:managedObject];
        NSError *error = NULL;
        Boolean success = [self.moc save:&error];
        if (!success) { <snip> }
        // actual row deletion from table view will be handle from Fetched Result Controller delegate
        // [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
    } else { <snip> }   
}

这将导致调用NSFetchedResultsController委托方法:

- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
   atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
  newIndexPath:(NSIndexPath *)newIndexPath
{
    UITableView *tableView = self.tableView;
    switch(type) {

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

        case NSFetchedResultsChangeInsert: <snip> break;
        case NSFetchedResultsChangeUpdate: <snip> break;
        case NSFetchedResultsChangeMove: <snip> break;
    }
}

当然,数据源方法由NSFetchedResultsController处理,例如:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    id <NSFetchedResultsSectionInfo> sectionInfo = [[self.fetchedResultsController sections] objectAtIndex:section];
    return [sectionInfo numberOfObjects];
}

非常感谢。

3 个答案:

答案 0 :(得分:2)

您似乎正在从表中删除indexPath,但表数据源未更新。 您是否通过NSFetchedResultsController验证数据源udation过程是否正确更新了表数据源。?

答案 1 :(得分:0)

我会这样做,因为您直接从托管上下文填充表,为什么不首先删除托管上下文中的对象,然后使用reloadData从上下文中立即更新表。但是使用您的方法我认为您需要添加beginUpdatesendUpdates

#pragma mark -
#pragma mark Fetched results controller delegate


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


- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
       atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {

switch(type) {
    case NSFetchedResultsChangeInsert:
        [self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeDelete:
        [self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex] withRowAnimation:UITableViewRowAnimationFade];
        break;
}
}


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

UITableView *tableViews = self.tableView;

switch(type) {

    case NSFetchedResultsChangeInsert:
        [tableViews insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeDelete:
        [tableViews deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        break;

    case NSFetchedResultsChangeUpdate:
        [_delegate configureCell:[tableViews cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
        break;

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


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView endUpdates];
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
    [self.tableView scrollToRowAtIndexPath:indexPath
                      atScrollPosition:UITableViewScrollPositionMiddle
                              animated:NO];
}

答案 2 :(得分:-1)

我在表视图中使用CoreData并允许用户一直删除记录并更新它们,我将它们放在4个应用程序中,而不会遇到您提到的问题。

我的代码中有这些FetchedResultsController委托方法

     - (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
  // The fetch controller is about to start sending change notifications, so prepare the table view for updates.
    [self.myTableView beginUpdates];
 }


- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    // The fetch controller has sent all current change notifications, so tell the table view to process all updates.
        [self.myTableView endUpdates];

}