NSFetchedResultsController:删除 1 行使应用程序崩溃
Posted
技术标签:
【中文标题】NSFetchedResultsController:删除 1 行使应用程序崩溃【英文标题】:NSFetchedResultsController: delete 1 row crashes the app 【发布时间】:2014-01-19 21:22:23 【问题描述】:从由 NSFetchedResultsController 提供的 UITableView 中删除一行会导致我的应用崩溃。
错误是:
* -[UITableView _endCellAnimationsWithContext:] 中的断言失败,/SourceCache/UIKit/UIKit-2903.23/UITableView.m:1330 * 由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'无效更新:第0节中的行数无效。更新后现有节中包含的行数(1)必须等于数字更新前该节中包含的行数 (1),加上或减去从该节插入或删除的行数(0 插入,1 删除),加上或减去移入或移出该节的行数(0迁入,0迁出)。'
我只想滑动删除。我的删除代码是这样的:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
[self.tableView beginUpdates];
SequenceData *sd = [self.fetchedResultsController objectAtIndexPath:indexPath];
[self.managedObjectContext deleteObject:sd];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
我的 NSFetchedResultsController 的设置与 Ray Wanderlich 的教程 (http://www.raywenderlich.com/999/core-data-tutorial-for-ios-how-to-use-nsfetchedresultscontroller) 中的一样
行数取决于:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
id sectionObjects = [[self.fetchedResultsController sections] objectAtIndex:section];
NSInteger nbObjects = [sectionObjects numberOfObjects];
return nbObjects;
看起来 fetch 没有更新(行数没有变化)。我需要自己获取(这不是由获取控制器处理的)吗?
显然我在这里缺少一些基本的东西。不要犹豫,提出基本的答案。
我首先用控制器实现了这个:didChangeObject: ... 方法。错误是一样的,但有些细节不同。
编辑 我相信我的问题已经解决了。两个答案(来自 CX 和 Martin)都帮助我找到了答案。马丁得到了答案,因为这些解释帮助我更好地理解了一点......
【问题讨论】:
【参考方案1】:不要打电话
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
如果您使用获取的结果控制器。只用
删除对象[self.managedObjectContext deleteObject:sd];
获取结果控制器委托方法然后自动调用didChangeObject:
,
并调用deleteRowsAtIndexPaths:
。
因此,在您的情况下,该行被删除了两次,这导致了异常。
请注意,这里不需要beginUpdates
/endUpdates
。
【讨论】:
谢谢。实施您的答案不会再使应用程序崩溃,但不会从表视图中删除该行。但是数据被删除了。我需要任何类型的 didChangeObject 实现吗? @invalidArgument:是的,您必须实现 4 个获取结果控制器委托方法。看看“还有一件事——我们需要实现 NSFetchedResultsController 的委托方法” 和教程中的以下代码。 - 它也记录在developer.apple.com/library/ios/documentation/CoreData/…。 实施这些方法会使我的应用程序再次崩溃。所以在commitEditingStyle
中,我只是删除了对象。在didChangeObject
中,它是教程中的复制粘贴(因此在此处有deleteRowsAtIndexPaths
)。该行实际上引发了异常,indexPath 和 newIndexPath 均为零。 (我还加了controllerWillChanteContent
和controllerDidChangeContent
)
@invalidArgument:这很奇怪,indexPath
在 NSFetchedResultsChangeDelete 情况下不应该为 nil。【参考方案2】:
如果你想删除一行,你只需要删除 managedObject。
if (editingStyle == UITableViewCellEditingStyleDelete)
[self.managedObjectContext deleteObject:[self.fetchedResultsController objectAtIndexPath:indexPath]];
NSError *error = nil;
if (![self.managedObjectContext save:&error])
// handle error
删除托管对象会触发NSFetchResultController
委托方法,它们将更新tableView
。
编辑
你应该实现 NSFetchResultController 委托方法
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath
switch(type)
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
////
default:
break;
因为当您使用 NSFetchedResultsController 之类的数据源时,所有更改都必须来自那里,并且您的表只反映它们。
【讨论】:
谢谢。我对您的建议的回答与我给马丁的回答类似。数据被删除,但行不会消失。我应该寻找什么? 你在实现 NSFetchResultController 的委托吗...? 是的,我是。controllerWillChangeContent
、controller: didChangeObject: ...
和 controllerDidChangeContent
你用我最新的编辑更新代码了吗,你是在 didChange 还是 willChange 中调用[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
,你应该把它加到一个更好的地方,你要添加 didChange ....
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
在controller: didChangeObject:
的NSFetchedResultsChangeDelete
案例中实现。在willChange
和didChange
里面我分别做[self.tableView beginUpdates]
和[self.tableView endUpdates]
。以上是关于NSFetchedResultsController:删除 1 行使应用程序崩溃的主要内容,如果未能解决你的问题,请参考以下文章