【发布时间】:2014-01-14 10:16:41
【问题描述】:
我有一个由NSFetchedResultsController 实例的核心数据备份的表视图。
此表有一个显示过滤数据的搜索栏。搜索栏有一个单独的 NSFetchedResultsController(从现在开始为 FRC)实例。
到目前为止一切顺利,数据已按预期获取并显示在表格视图中,并且在搜索栏的表格视图中也正确显示(搜索数据时)。
我的问题是,如果我尝试在搜索栏的表格视图中删除一个单元格,则会收到 coredata 异常:
错误:严重的应用程序错误。从 调用期间 NSFetchedResultsController 的委托 -controllerDidChangeContent:。尝试从第 0 部分中删除第 0 行,该部分在使用 userInfo (null) 进行更新之前仅包含 0 行
进一步检查表明,FRC 的controllerWillChangeContent 方法在一个单元格删除时被调用了两次!。这会导致 deleteRowsAtIndexPaths 为同一个单元格调用两次(因此是 coredata 异常)。
再玩一会我发现这个问题是在搜索后第一次显示搜索栏的表格视图时发生的。 (即使我返回并删除常规表格视图中的单元格也会出现问题)
我已确保 deleteRowsAtIndexPaths 方法在代码中仅被调用一次(在 FRC 的 didChangeObject 委托方法中)。
现在我不确定要显示哪个代码,所以我不会全部泄露。如果您知道问题所在,请告诉我您需要查看哪一个。
这是指示表删除行的代码:
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
DLog(@"didChangeObject type %lu with object %@", (unsigned long)type, anObject);
switch(type) {
case NSFetchedResultsChangeInsert:
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[self.tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath forTable:self.tableView];
break;
case NSFetchedResultsChangeMove:
[self.tableView deleteRowsAtIndexPaths:[NSArray
arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[self.tableView insertRowsAtIndexPaths:[NSArray
arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
删除所选单元格的对象后保存上下文时调用此方法。
我保存上下文的方法:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_managedObjectContext deleteObject:[_notesFetcher objectAtIndexPath:indexPath]];
NSError *error;
if (![_managedObjectContext save:&error]) {
DLog(@"Failed deleting object : %@", [error localizedDescription]);
}
}
}
由于某种原因,此方法被调用了一次,但对同一单元格使用相同的更改类型(2-Delete)调用了两次didChangeObject。
更新
当我在方法 didChangeObject 中记录堆栈跟踪时,我得到了这个:
[UITableView animateDeletionOfRowWithCell:] + 107 12 UIKit
0x01316a35-[UITableViewCell_swipeDeleteButtonPushed] + 70 13 libobjc.A.dylib 0x02346874 -[NSObject performSelector:withObject:withObject:] + 77 14 UIKit
0x010a8c8c -[UIApplication sendAction:to:from:forEvent:] + 108 15 UIKit 0x010a8c18 -[UIApplication sendAction:toTarget:fromSender:forEvent:] + 61 16 UIKit
0x011a06d9 -[UIControl sendAction:to:forEvent:] + 66 17 UIKit
0x011a0a9c-[UIControl_sendActionsForEvents:withEvent:] + 577 18 UIKit 0x0119fd4b -[UIControl touchesEnded:withEvent:] + 641 19 UIKit
0x0141ad7f _UIGestureRecognizerUpdate + 7166 20 UIKit
0x010e5d4a -[UIWindow _sendGesturesForEvent:] + 1291 21 UIKit
0x010e6c6a -[UIWindow sendEvent:] + 1030 22 UIKit
0x010baa36 -[UIApplication sendEvent:] + 242 23 UIKit
0x010a4d9f _UIApplicationHandleEventQueue + 11421
如您所见,表的swipeDeleteButtonPushed 方法在一次删除操作中被调用两次,如上所述。当我只按一次删除按钮时,如何触发两次?有什么想法吗?
【问题讨论】:
-
能否给出删除表格视图行的代码?
-
我的猜测是您使用 2 个 FRC 和相同的控制器进行搜索和常规视图。在您的“更新”方法中,您将同一张表更新两次。
-
@MartinR 我添加了相关的删除发生的地方
-
@DanShelly 实际上,我使用相同的控制器作为两个 FRC 的代表,但我确实在需要时使用了正确的控制器(搜索和选择单元格调用正确的 segue 并显示正确的数据)我在某处读到
self.tableView始终指向当前表视图(即,如果显示搜索栏的表视图,则self.tableView将指向该表)并且应该在表的委托方法中使用。 -
@giorashc:这是不正确的。您必须更新
self.tableView(始终是“主”表视图)或self.searchDisplayController.searchResultsTableView,具体取决于搜索是否处于活动状态。所以@Dan 似乎走在了正确的轨道上。
标签: core-data ios7 tableview searchbar