【问题标题】:tableView:cellForRowAtIndexPath called with nil indexPath after deleting item删除项目后使用 nil indexPath 调用 tableView:cellForRowAtIndexPath
【发布时间】:2011-08-04 12:27:53
【问题描述】:

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

当用户通过滑动删除表视图中的条目时,tableView:cellForRowAtIndexPath: 最终会在我的UITableViewController 上调用nil 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];
}

非常感谢。

【问题讨论】:

  • 您是否验证了所有这些都以预测的顺序被调用?
  • 尝试在tableView:commitEditingStyle:forRowAtIndexPath 中的表视图上立即调用reloadData 保存对托管对象上下文的更改。我遇到了类似的问题并重新加载表格视图修复了它。

标签: ios null nsindexpath uitableview


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    我会这样做,因为您是直接从托管上下文中填充表,为什么不在删除时首先从托管上下文中删除对象,然后立即使用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];
    }
    

    【讨论】:

      【解决方案3】:

      我在表视图中使用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];
      

      }

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-24
        • 1970-01-01
        • 1970-01-01
        • 2015-08-30
        • 1970-01-01
        • 1970-01-01
        • 2020-08-18
        • 1970-01-01
        相关资源
        最近更新 更多