删除行时应用程序崩溃
我的表用于列出核心数据中的行。一切正常,我使用了两种类型的数据加载到同一个表视图上。数据类型会因范围按钮的变化而变化。两个范围按钮,一个显示已完成的任务,另一个显示待处理的任务。我可以在桌子上搜索、更新。虽然只有完整的数据列表是可编辑和可以删除的,但有时它工作正常,有时会给出错误,
Serious application error. An exception was caught from the delegate of
NSFetchedResultsController during a call to -controllerDidChangeContent:. *** -
[NSMutableArray insertObject:atIndex:]: index 4 beyond bounds for empty array with
userInfo (null)
获取结果控制器初始化为,
- (NSFetchedResultsController *)fetchedResultsControllerWithPredicate:(NSPredicate *)predicate{
if (self.fetchedResultsControl != nil) {
NSLog(@"Here I am outside");
return self.fetchedResultsControl;
}
加载表视图单元格的代码如下:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
CustomCell *cell =(CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects=[[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil];
for (id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[UITableViewCell class]]){
cell=(CustomCell *)currentObject;
break;
}
}
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
并且更新方法称为通过 NSFetchedResultsControllerDelegate 如下:
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.listingTable beginUpdates];
NSLog(@"Changed content");
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id < NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.listingTable insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.listingTable deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
NSLog(@"Changed content switch case");
UITableView *tableView = self.listingTable;
switch(type) {
case NSFetchedResultsChangeInsert:
[self.listingTable insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[self.listingTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(CustomCell *)[tableView cellForRowAtIndexPath:indexPath]
atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[self.listingTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.listingTable insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
NSLog(@"Changed Content");
[self.listingTable endUpdates];
}
My table is used to list the rows from the core data. Everything works fine, I have used two types of data to load on the same table view. The data types change on account of the scope button change. Two scope buttons one displays completed tasks while other displays pending taks. I can search, update on the table. While only completed list of datas are editable and can be deleted, sometimes it works fine and sometimes it gives error as such,
Serious application error. An exception was caught from the delegate of
NSFetchedResultsController during a call to -controllerDidChangeContent:. *** -
[NSMutableArray insertObject:atIndex:]: index 4 beyond bounds for empty array with
userInfo (null)
The fetch result controller is initialised as,
- (NSFetchedResultsController *)fetchedResultsControllerWithPredicate:(NSPredicate *)predicate{
if (self.fetchedResultsControl != nil) {
NSLog(@"Here I am outside");
return self.fetchedResultsControl;
}
The code to load the cell for tableview is as :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = @"Cell";
CustomCell *cell =(CustomCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
NSArray *topLevelObjects=[[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:nil options:nil];
for (id currentObject in topLevelObjects) {
if([currentObject isKindOfClass:[UITableViewCell class]]){
cell=(CustomCell *)currentObject;
break;
}
}
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
And the update method called by the NSFetchedResultsControllerDelegate is as;
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller {
[self.listingTable beginUpdates];
NSLog(@"Changed content");
}
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id < NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type {
switch(type) {
case NSFetchedResultsChangeInsert:
[self.listingTable insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.listingTable deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath {
NSLog(@"Changed content switch case");
UITableView *tableView = self.listingTable;
switch(type) {
case NSFetchedResultsChangeInsert:
[self.listingTable insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationTop];
break;
case NSFetchedResultsChangeDelete:
[self.listingTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:(CustomCell *)[tableView cellForRowAtIndexPath:indexPath]
atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[self.listingTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[self.listingTable insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
NSLog(@"Changed Content");
[self.listingTable endUpdates];
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我没有看到任何明显的错误,但在一个表视图中交换两个逻辑表是一种危险的设计,因为你必须非常小心,表视图知道它的逻辑表已被更改。
您收到的错误表明表视图正在使用一个逻辑表的索引之一来配置自身,但实际上正在访问第二个逻辑表的数组,该数组较短。
您的直接解决方案是仔细查看
numberOfSections
和numberOfRowsInSection
等方法,以确保在切换逻辑表时这些方法正确更新。最好的设计解决方案是使用两个单独的表视图及其自己单独的数据源,然后根据需要交换它们。
I don't see any obvious errors but swapping out two logical tables in one tableview is a dangerous design because you have to be very careful that tableview knows that its logical table has been changed.
The error you are getting suggest that the tableview is configuring itself using one the index of one logical table but is actually accessing the array of the second logical table which is shorter.
Your immediate solution it to look closely at the methods like
numberOfSections
andnumberOfRowsInSection
to make sure that those update properly when you switched logical tables.The best design solution is to use two separate tableviews with their own separate data source and then swap them out as needed.