删除项目后使用 nil indexPath 调用 tableView:cellForRowAtIndexPath
Posted
技术标签:
【中文标题】删除项目后使用 nil indexPath 调用 tableView:cellForRowAtIndexPath【英文标题】:tableView:cellForRowAtIndexPath called with nil indexPath after deleting item 【发布时间】: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
, 保存对托管对象上下文的更改。我遇到了类似的问题并重新加载表格视图修复了它。
【参考方案1】:
您似乎正在从表中删除 indexPath,但表数据源并未更新。 您是否验证了 NSFetchedResultsController 的数据源更新过程是否正确更新了表数据源?
【讨论】:
【参考方案2】:我会这样做,因为您是直接从托管上下文中填充表,为什么不在删除时首先从托管上下文中删除对象,然后立即使用reloadData
从上下文中更新表。但是使用您的方法,我认为您需要添加beginUpdates
和endUpdates
:
#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];
【讨论】:
以上是关于删除项目后使用 nil indexPath 调用 tableView:cellForRowAtIndexPath的主要内容,如果未能解决你的问题,请参考以下文章
由于未捕获的异常“NSInternalInconsistencyException”而终止应用程序,原因:“无效参数不满足:indexPath!= nil”
在按钮功能Swift中访问indexPath.row [重复]