- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我有 2 个托管对象上下文:(1) 创建为 NSMainQueueConcurrencyType
,供 UI/主线程使用,(2) 创建为 NSPrivateQueueConcurrencyType
,供 UI/主线程使用网络。这两个上下文都进入持久存储(即,我没有使用父/子上下文)。
对于 View Controller ,我使用一个 UITableViewController
和一个使用第一个 UI 管理对象上下文的 NSFetchedResultsController
。
我正在通过观察 NSManagedObjectContextDidSaveNotification
将第二个托管对象上下文中的更改合并到第一个上下文中。
应用程序工作正常,直到它处理网络响应,导致在第二个上下文中插入新对象和删除现有对象。当第二个上下文被保存时,NSManagedObjectContextDidSaveNotification
触发并且更改被合并到第一个上下文中。 NSFetchedResultsController
的委托(delegate)方法被调用,一个新行被添加到表中,但是表示已删除对象的行*没有被删除。
如果我尝试对 TableView 执行其他操作,例如重新加载表或更新其他对象,我会在控制台日志中得到此断言:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:],
/SourceCache/UIKit/UIKit-2380.17/UITableView.m:1070
CoreData: error: Serious application error. An exception was caught
from the delegate of NSFetchedResultsController during a call to -
controllerDidChangeContent:. Invalid update: invalid number of rows in
section 0. The number of rows contained in an existing section after the
update (6) must be equal to the number of rows contained in that section
before the update (7), plus or minus the number of rows inserted or deleted
from that section (6 inserted, 6 deleted) and plus or minus the number of rows
moved into or out of that section (0 moved in, 0 moved out). with
userInfo (null)
通常,如果您在使用 UITableView
的批量更新方法时忘记更新您的模型对象,您会收到此错误,但在这种情况下,NSFetchedResultsController
正在做所有的工作。我的委托(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
{
NSLog(@" didChangeObject type=%d indexPath=%@ newIndexPath=%@", type, indexPath, newIndexPath);
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:@[newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
我的 UITableViewDataSource tableView:cellForRowAtIndexPath
方法是:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
configureCell:
是:
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath
{
Event *event = (Event *)[self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [[event valueForKey:@"timeStamp"] description];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Owner"];
NSArray *objects = [self.managedObjectContext executeFetchRequest:fetchRequest error:nil];
cell.detailTextLabel.text = [objects.lastObject name]; // simplified
}
最佳答案
如果您在准备响应 tableView:cellForRowAtIndexPath:
的单元格时使用 NSFetchRequest
,
NSFetchedResultsController
会非常困惑。如果您不执行 NSFetchRequest
,一切都很好。但是,如果您这样做,它会触发 NSFetchedResultsController
执行进一步的更改通知,这会对 UITableView
造成不良影响。
解决方法是在 NSFetchRequest 上设置 includesPendingChanges = NO
。
我已经打开了一个关于这个的雷达问题——问题 id 14048101
——有一个详细的例子和示例应用程序。此错误在 iOS 5.1、6.0 和 6.1 上重现。
在我的示例应用程序中,我将日志记录添加到 Xcode 的 CoreData 模板以记录 NSFetchedResultsController
委托(delegate)方法的进入/离开。当我在网络上下文中插入和删除对象时,日志记录显示:
01:=>(之前)mergeChangesFromContextDidSaveNotification02:=>(输入)controllerWillChangeContent count=403:<=(离开)controllerWillChangeContent count=404: didChangeObject type=1 indexPath=(null) newIndexPath= 2 索引 [0, 0]05: => (输入) controllerDidChangeContent count=5
此时,一切都很好。 controllerDidChangeContent:
已被调用以处理 1 插入,它调用 [tableView endUpdates]
,它调用 tableView:cellForRowAtIndexPath:
,它调用 configureCell:atIndexPath:
.
06: =>(输入)在第 0 行配置单元格
此时,configureCell:atIndexPath:
创建了一个 NSFetchRequest
并调用了 [self.managedObjectContext executeFetchRequest:error:]
—— 此处开始坏处。执行此获取请求会在插入处理完成之前触发上下文中剩余更改的处理(1 次删除和 3 次更新)(我们在第 05 行输入 controllerDidChangeContent:
直到第 16 行)。
07: => (输入) controllerWillChangeContent count=508:<=(离开)controllerWillChangeContent count=509: didChangeObject type=2 indexPath= 2 索引 [0, 4] newIndexPath=(null)10: didChangeObject type=4 indexPath= 2 索引 [0, 2] newIndexPath=(null)11: didChangeObject type=4 indexPath= 2 索引 [0, 1] newIndexPath=(null)12: didChangeObject type=4 indexPath= 2 索引 [0, 3] newIndexPath=(null)13: => (输入) controllerDidChangeContent count=4
此时,框架正在对controllerDidChangeContent:
进行重入调用。
14: <= (离开) controllerDidChangeContent count=415:<=(离开)在第 0 行配置单元格16:<=(离开)controllerDidChangeContent 计数=417:<=(在)mergeChangesFromContextDidSaveNotification
此时,您可以在 UI 中看到:(1) 添加了一个新单元格,(2) 更新了 3 个单元格,(3) 已删除的单元格仍然可见,这是错误的。
在 UI 中进一步操作后,我通常会收到 断言失败
或发送到无效对象异常的消息。
我的示例应用程序位于 https://github.com/peymano/CoreDataFetchedResultsController
关于ios - -[UITableView _endCellAnimationsWithContext :] with NSFetchedResultsController 中的断言失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16905935/
我充其量只是一个业余爱好者,并坚持这个错误!肯定是一些简单的事情...... - (void)addTapped:(id)sender { TechToolboxDoc *newDoc = [[Tec
这个问题在这里已经有了答案: 'Invalid update: invalid number of rows in section 0 (5 个答案) 关闭 9 年前。
我正在解析一个 xml 文件并将其解析的值放在 TableView 中。 TableView 只有一个部分。但我遇到以下异常: 2013-10-14 15:21:57.250 tableview[60
希望这能快速解决。我一直在试图找出我不断遇到的错误。下面列出了错误,应用程序延迟在下面。 感谢任何帮助。 谢谢 2012-04-12 21:11:52.669 Chanda[75100:f803] -
我有 2 个托管对象上下文:(1) 创建为 NSMainQueueConcurrencyType,供 UI/主线程使用,(2) 创建为 NSPrivateQueueConcurrencyType,供
希望这将是一个快速修复。我一直在试图找出我不断遇到的错误。错误在下面列出,appdelagate 在下面。 感谢任何帮助。 谢谢 2012-04-12 21:11:52.669 Chanda[7510
我的应用程序崩溃,并显示在该线程标题中的消息。 UITableView.m中的断言失败。此外,在Xcode的调试窗口中还有以下消息。 Terminating app due to uncaught e
当我在 View Controller 或表格 View Controller 中回击时出现此错误。 返回是导航栏上的一个栏按钮项目,它被返回到前一个 Controller 或我的主目录 tablev
我正在实现一个 UITableView。我也在使用 CoreData。它工作正常但是当我尝试删除一行时出现此错误: Assertion failure in -[UITableView _endCel
我正在使用 UITableView 向用户显示一些设置。当重新加载一个部分或插入一些带有动画的行时,可能会在委托(delegate)/数据源函数中出错导致 Assertion failure in -
从我的 PFTableViewController 中删除图像时出现此错误。我已经进行了广泛的搜索,据我所知,commitEditingStyle 中的代码是正确的。谁能帮忙? import Foun
我在转换为 Swift 的一些代码时遇到了一个大问题。调用 self.tableView.endUpdates() 时,我的 TableView 保持为空,并且出现以下错误: Assertion fa
我愿意删除单元格并在PFQueryViewController的单元格中显示重载tableView。 但是,当我删除并刷新TableView时,出现错误:“***-[UITableView _endC
应用程序将照片上传到服务器。 当用户选择上传某些照片时,照片的信息将保存到核心数据中。使用 fetchedResultsController 填充一个表格 View ,显示照片列表。 表格 View
我在 UITablViewSource 中使用以下代码 public override UITableViewCell GetCell (UITableView tableView, NSIndex
我正在项目中实现一个可编辑的表格 View 。当我点击左侧滑动后显示的红色 Delete 按钮时,应用程序崩溃了。控制台日志在这里: *** -[UITableView _endCellAnimati
我是一名优秀的程序员,十分优秀!